出现该报错条件:接口返回数据量比较大,然后对数据进行了SM4加密,所导致的报错。
网上常规解决思路:java虚拟机内存不够,修改jvm的启动参数。
-Xms258m -Xmx2048m
确实可以解决该问题,当我把内存放到4096M时,我的报错消失了。但是,问题随之而来,如果我的数据量更大时。是不是需要继续扩容呢?这虽然是一种解决方式,但可能有更好的解决方式。
于是,我重新定位问题,首先是我的加密写法如下
@PostMapping("/encrypt/sm4")
public ResultWrapper sm4(@RequestBody EncryptInfo encryptInfo) throws Exception {
String data = encryptInfo.getData();
String key = encryptInfo.getKey();
log.info("sm4加密参数data:{},key:{}", data, key);
byte[] dataBytes = Base64.decodeBase64(data);
byte[] keyBytes = Base64.decodeBase64(key);
byte[] encrypt = Sm4Util.encrypt(keyBytes, dataBytes);
return ResultWrapper.success(ByteUtils.toHexString(encrypt));
}
最终问题是出在了ByteUtils.toHexString这个方法上,包内的方法写法是用位运算实现的
public static String toHexString3(byte[] bytes) {
char[] buf = new char[bytes.length * 2];
int index = 0;
// 利用位运算进行转换
for (byte b : bytes) {
buf[index++] = HEX_CHAR[b >>> 4 & 0xf];
buf[index++] = HEX_CHAR[b & 0xf];
}
return new String(buf);
}
然后,我自定义了该方法,通过字符串拼接实现,如下
public static String toHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
int num;
for (byte b : bytes) {
num = b < 0 ? 256 + b : b;
sb.append(HEX_CHAR[num / 16]).append(HEX_CHAR[num % 16]);
}
return sb.toString();
}
最终解决了该问题。
java byte数组与16进制间相互转换参考博客:https://www.jb51.net/article/198049.htm
有一个疑问还未解决:位运算主要是直接操控二进制时使用 ,主要目的是节约内存,使你的程序速度更快,但为何我使用位运算方法的转换出现了溢出,反而使用字符串拼接的方法能够正常走完流程。
总结:记录该问题并不是因为,这个bug有多难,更关键的是其中的思路转变,不要为了解决问题而去解决问题,去寻找到问题的根源,要对症下药,提醒自己以后如何面对新的问题。