写在之前
这篇文章是上一篇文章的后续事件,记录的事情也挺有意思。想看事情如何开始的点击链接
频繁GC引起卡顿问题排查与解决
进入正题
不知道有没有人遇到过编译后部分代码缺失呢?反正我遇到了, 上一篇文章提到了因为开发人员写了死循环造成系统卡死。问题代码如下,此方法缺少tempStart.add(calendarField, 1)变成了死循环
--startTime1开始时间
--endTime1 截止时间
--开发人员写了一个方法获取两个时间的中间天数 - -# 大致代码如下
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
int calendarField=Calendar.DAY_OF_MONTH;
Calendar tempStart = Calendar.getInstance();
tempStart.setTime(startTime1);
while (endTime1.getTime() >= startTime1.getTime()) {
dateList.add(format.format(startTime1));
tempStart.add(calendarField, 1); //没有此行时候死循环
startTime1 = tempStart.getTime();
}
起初,我以为本事故只是开发人员漏提交了代码引起的偶然事情,然而并不是如此。 我再三确认代码库里已经提交了tempStart.add(calendarField, 1) 并非死循环后重新构建并请测试组继续验证。结果同样的问题又出现了。使用Arthas反编译后发现又是之前的问题,因缺少tempStart.add(calendarField, 1)造成死循环。
/*274*/ Calendar tempStart = Calendar.getInstance();
/*275*/ tempStart.setTime(startTime1);
while (endTime1.getTime() >= startTime1.getTime()) {
/*277*/ dateList.add(format.format(startTime1));
/*279*/ startTime1 = tempStart.getTime();
}
经过反复确认测试环境使用的包无问题,甚至自己重新使用jenkins构建并反编译确认。结果:代码库里有tempStart.add(calendarField, 1)代码, 但是构建后的程序包反编译没有tempStart.add(calendarField, 1)。 这种诡异事情还真我遇到了
提交的代码
编译后的代码
世界真精彩!
我开始以为是编译问题,此工程编译使用的是1.6,我写了一个测试类来验证我的想法,参考代码如下
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
public class Test1 {
public static void main(String[] args) {
try {
List<String> dateList = new ArrayList<String>();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
int calendarField=Calendar.DAY_OF_MONTH;
String startTime = "20230420";
String endTime = "2023042601";
Date startTime1 = format.parse(startTime);
Date endTime1 = format.parse(endTime.substring(0,startTime.length()));
Calendar tempStart = Calendar.getInstance();
tempStart.setTime(startTime1);
System.out.println("first"+startTime1);
while (endTime1.getTime() >= startTime1.getTime()) {
dateList.add(format.format(startTime1));
tempStart.add(calendarField, 1);
startTime1 = tempStart.getTime();
}
} catch (Exception e) {
// log.error(e);
}
}
}
分别使用1.6和1.8和17编译
D:\>javac Test1.java
D:\>
编译后反编译class发现1.6,1.8,17处理结果相同,而 localCalendar.add(i, 1)代码正常
public class Test1
{
public static void main(String[] paramArrayOfString)
{
try
{
java.util.ArrayList localArrayList = new java.util.ArrayList();
java.text.SimpleDateFormat localSimpleDateFormat = new java.text.SimpleDateFormat("yyyyMMdd");
int i = 5;
String str1 = "20230420";
String str2 = "2023042601";
java.util.Date localDate1 = localSimpleDateFormat.parse(str1);
java.util.Date localDate2 = localSimpleDateFormat.parse(str2.substring(0, str1.length()));
java.util.Calendar localCalendar = java.util.Calendar.getInstance();
localCalendar.setTime(localDate1);
System.out.println("first" + localDate1);
while (localDate2.getTime() >= localDate1.getTime()) {
localArrayList.add(localSimpleDateFormat.format(localDate1));
localCalendar.add(i, 1);
localDate1 = localCalendar.getTime();
}
}
catch (Exception localException) {}
}
}
从网上也搜了搜,但没有同学遇到类似问题,也没有相应的文章。还好在排查问题过程中发现java类提交的时候使用的是utf-8 ,我就怀疑是不是编码格式问题, 从代码库里拷贝出问题源文件,然后修改成测试类,下载后发现因为java类是UTF-8提交的代码。中文已经变成了乱码
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
public class Test {
public static void main(String[] args) {
try {
List<String> dateList = new ArrayList<String>();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
int calendarField=Calendar.DAY_OF_MONTH;
String startTime = "20230420";
String endTime = "2023042601";
Date startTime1 = format.parse(startTime);
Date endTime1 = format.parse(endTime.substring(0,startTime.length()));
Calendar tempStart = Calendar.getInstance();
tempStart.setTime(startTime1);
System.out.println("first"+startTime1);
while (endTime1.getTime() >= startTime1.getTime()) {
dateList.add(format.format(startTime1));
//鏈夊绉嶆ā寮忓彲浠ュ鍔犳垨鍑忓幓鐩稿簲鐨勬椂闂�
tempStart.add(calendarField, 1);
startTime1 = tempStart.getTime();
}
} catch (Exception e) {
// log.error(e);
}
}
}
编译测试时发现编译警告,并且在警告后有丢失的代码信息。如下
D:\>javac Test.java
Test.java:28: 警告:编码 GBK 的不可映射字符
//閺堝顧嬬粔宥喣佸蹇撳讲娴犮儱顤冮崝鐘冲灗閸戝繐骞撻惄绋跨安閻ㄥ嫭妞傞梻锟? tempStart.add(calendarField, 1);
^
1 警告
再将Test.class反编译,发现tempStart.add(calendarField, 1)这条命令丢失了
从现象上看乱码后的1行代码被当做了乱码信息
package com.star.sms.business.customer.job;
import java.io.PrintStream;
import java.util.List;
public class Test
{
public static void main(String[] paramArrayOfString)
{
try
{
java.util.ArrayList localArrayList = new java.util.ArrayList();
java.text.SimpleDateFormat localSimpleDateFormat = new java.text.SimpleDateFormat("yyyyMMdd");
int i = 5;
String str1 = "20230420";
String str2 = "2023042601";
java.util.Date localDate1 = localSimpleDateFormat.parse(str1);
java.util.Date localDate2 = localSimpleDateFormat.parse(str2.substring(0, str1.length()));
java.util.Calendar localCalendar = java.util.Calendar.getInstance();
localCalendar.setTime(localDate1);
System.out.println("first" + localDate1);
while (localDate2.getTime() >= localDate1.getTime()) {
localArrayList.add(localSimpleDateFormat.format(localDate1));
localDate1 = localCalendar.getTime();
}
}
catch (Exception localException) {}
}
}
故事结尾
本问题是由于注释乱码引起了编译错误,开发过程中以下两点十分重要
1)开发人员都希望别人多写注释,那么自己写注释时,必须注意乱码问题
2)特殊符号使用国际化文件,这样可以有效的避免乱码
上一篇:频繁GC引起卡顿问题排查与解决