简化版代码:
package com.mystic.ycc.blog.test;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
public class TestOOM {
/**
* @param args
*/
public static void main(String[] args) {
// testAESOOM();
testMap();
}
/**
* jvm 参数:-Xmx2048m -Xms512m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=file.hprof
* 打开JVISUALVM 可以看到JDK的自调整(没有配置其他参数的情况下)
*/
public static void testMap(){
Map<Integer, HashSet<String>> masterMap = new HashMap<>(100000);
for (int i = 0; i < 100000; i++) {
System.out.println(i);
masterMap.computeIfAbsent(i, HashSet::new).add("test"+i);
}
}
/**
*jvm 参数:-Xmx512m -Xms512m 避免jdk自调整 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=file.hprof
* <dependency>
* <groupId>org.bouncycastle</groupId>
* <artifactId>bcprov-jdk15on</artifactId>
* <version>1.70</version>
* </dependency>
*/
public static void testAESOOM(){
try {
String key = "1234567890123456"; // 16字节密钥
String iv = "abcdefghijklmnop"; // 16字节IV
String plainText = "Hello, BouncyCastle!";
for (int i = 0; i < 100000; i++) {
// 加密
String encryptedText = encrypt(plainText, key, iv);
System.out.println("加密后的数据: " + encryptedText);
// 解密
String decryptedText = decrypt(encryptedText, key, iv);
System.out.println("解密后的数据: " + decryptedText);
}
} catch (Exception e) {
e.printStackTrace();
}
}
// AES加密模式为CBC,填充方式为PKCS5Padding
private static final String AES_CBC_PKCS5_PADDING = "AES/CBC/PKCS5Padding";
// 密钥和IV(初始化向量)的长度必须为16字节(128位)
private static final int KEY_LENGTH = 16;
private static final int IV_LENGTH = 16;
/**
* AES加密
* @param plainText 明文
* @param key 密钥
* @param iv 初始化向量
* @return 加密后的Base64编码字符串
* @throws Exception 加密过程中的异常
*/
public static String encrypt(String plainText, String key, String iv) throws Exception {
// 检查密钥和IV的长度
if (key.length() != KEY_LENGTH || iv.length() != IV_LENGTH) {
throw new IllegalArgumentException("密钥和IV的长度必须为16字节(128位)");
}
// 创建AES密钥
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
// 创建初始化向量
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
BouncyCastleProvider bouncyCastleProvider = new BouncyCastleProvider();
// 创建Cipher对象并初始化为加密模式
Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5_PADDING, bouncyCastleProvider); // 使用BouncyCastle Provider
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
// 加密数据
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));
// 返回Base64编码的加密数据
return Base64.getEncoder().encodeToString(encryptedBytes);
}
/**
* AES解密
* @param encryptedText 加密的Base64编码字符串
* @param key 密钥
* @param iv 初始化向量
* @return 解密后的明文
* @throws Exception 解密过程中的异常
*/
public static String decrypt(String encryptedText, String key, String iv) throws Exception {
// 检查密钥和IV的长度
if (key.length() != KEY_LENGTH || iv.length() != IV_LENGTH) {
throw new IllegalArgumentException("密钥和IV的长度必须为16字节(128位)");
}
// 创建AES密钥
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
// 创建初始化向量
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
BouncyCastleProvider bouncyCastleProvider = new BouncyCastleProvider();
// 创建Cipher对象并初始化为解密模式
Cipher cipher = Cipher.getInstance(AES_CBC_PKCS5_PADDING, bouncyCastleProvider); // 使用BouncyCastle Provider
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
// 解码Base64并解密数据
byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
// 返回解密后的明文
return new String(decryptedBytes, StandardCharsets.UTF_8);
}
}
排查思路
- 使用工具 :IDEA,IDEA_Profile插件,JVM参数
- 必须配置参数:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=file.hprof
- JProfile工具
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。