【问题标题】:Memory issues/leaks in AES encryption/decryption of strings in javajava中字符串的AES加密/解密中的内存问题/泄漏
【发布时间】:2013-10-16 18:01:02
【问题描述】:

我的问题是我正在解密/加密来自不同线程的一些随机值字符串集,但经过多次迭代后内存迅速增加。
我的观察是内存增加是因为每次加密/解密都会产生新的字符串,因此内存会增加。
还有一点需要注意的是我的解密/加密字符串会有很多与相同的字符串集相同的值(某些字符串可能是新的)从许多线程中加密/解密,但由于在每个加密/解密中,密码返回字节数组并再次构成字符串,我必须使用“新字符串()”函数,这可能会或将迅速增加内存。
这是我加密/解密字符串的代码

public static String encrypt(String key, String value) throws GeneralSecurityException 
{

    byte[] raw = key.getBytes();
    if (raw.length != 16) {
        throw new IllegalArgumentException("Invalid key size.");
    }

    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
    byte[] cipherBytes= cipher.doFinal(value.getBytes());
    byte[] encoded =    org.apache.commons.codec.binary.Base64.encodeBase64(cipherBytes);
    return new String(encoded);

}

public static String decrypt(String key, String encrypted) throws GeneralSecurityException 
{

    byte[] raw = key.getBytes();
    if (raw.length != 16) {
        throw new IllegalArgumentException("Invalid key size.");
    }
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
    byte[] byteDecodedText =  org.apache.commons.codec.binary.Base64.decodeBase64(encrypted.getBytes()) ;

    byte[] original = cipher.doFinal(byteDecodedText);

    return new String(original);
}

【问题讨论】:

  • 您可以在从字节数组中提取String 后立即调用intern(),并删除对String 的所有引用。当然,String 会占用内存,直到它被垃圾回收,但我看不出你能做得比这更好。
  • @DavidWallace 这意味着我必须在 new String(byteDecryptedText) 上调用实习生;
  • 是的,很明显。但无论如何,您将不得不致电new String(byteDecryptedText)
  • @DavidWallace 我这样做了,但没有改善同样的内存峰值。
  • 我们不要在聊天中继续讨论。现在是凌晨 1 点。我需要去睡觉。也许其他人可以帮助你。或者你可以等我醒来。

标签: java string encryption


【解决方案1】:

确实,每次迭代都会产生新的字符串,但我认为这不会很快增加内存,因为字符串所需的内存以字节为单位。
根据String memory usage,您可以计算您加密或解密的字符串的大小。这可以让您了解内存增加是否是由于每次都形成新的字符串。

【讨论】:

  • 有效点,现在从不同的角度来研究问题
【解决方案2】:

字符串实习生方法可能是要走的路。它返回字符串的规范表示,因此对于相同的字符串,您将只有一个实例。 因此,当您返回一个字符串时,只需尝试这样做:

 new String(byteDecryptedText).intern();

您使用 new 创建的 String 的一个实例将在您离开范围后被收集。内部对象将被返回。

【讨论】:

  • 感谢您的回复,但它并没有解决问题,因为当我们调用 new String(byteDecryptedText) 时,已经在堆中创建了一个新字符串
  • 是的,它会在你从我认为可以的函数返回后被 gc 收集,因为没有对该实例的引用。所以总堆大小只会根据唯一的字符串而增长
  • 分配此代码后没有任何改善,内存继续增加,因为它之前增加了
  • 这可能是因为这两个函数生成的所有字符串都是唯一的。您确定大多数生成的字符串具有完全相同的内容吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-04
  • 1970-01-01
  • 2015-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多