1、问题描述
公司项目有上传2g压缩包(zip、rar)功能,其中zip压缩包功能直接使用linux命令解压没有问题,在RAR解压时恳求出现阻塞卡死的情况(直到情断恳求超时linux系统界面,恳请就会失败)linux的压缩命令,查看服务器日志解压命令如下:

/usr/local/bin/unrar X -o+ /data/temp/upload/xxx/2021/06/01/xxx_1622544204569.rar /data/temp/upload/xxx/2021/06/01

可以看出解压命令是没有错误的,于是去查看解压命令是否执行成功,找到解压目录,文件早已解压成功,如右图:
这么问题来了,为何解压成功后linux的压缩命令,程序卡死在解压的代码(Processproc=Runtime.getRuntime().exec(cmd))??解压的方式如下:

public static boolean realExtract(String zipFile, String destDir) { // 解决路径中存在/..格式的路径问题 destDir = new File(destDir).getAbsoluteFile().getAbsolutePath(); while (destDir.contains("..")) { String[] sepList = destDir.split("\\"); destDir = ""; for (int i = 0; i < sepList.length; i++) { if (!"..".equals(sepList[i]) && i < sepList.length - 1 && "..".equals(sepList[i + 1])) { i++; } else { destDir += sepList[i] + File.separator; } } } boolean bool = false; if (!FileUtil.exist(zipFile)) { return false; } if (!FileUtil.exist(destDir)) { FileUtil.mkdir(destDir); } //判断系统类型 开始调用命令行解压,参数-o+是表示覆盖的意思 String cmdPath = ""; String osName = System.getProperty("os.name"); if (osName.contains("Window")) { cmdPath = "C:\Program Files\WinRAR\WinRAR.exe"; } else { cmdPath = "/usr/local/bin/unrar"; } String cmd = cmdPath + " X -o+ " + zipFile + " " + destDir; System.out.println(cmd); try { Process proc = Runtime.getRuntime().exec(cmd); if (proc.waitFor() != 0) { if (proc.exitValue() == 0) { bool = false; } } else { bool = true; } } catch (Exception e) { log.error("解压失败:" + e.getMessage(), e); e.printStackTrace(); } System.out.println("解压" + (bool ? "成功" : "失败")); return bool; }

问题剖析

1、排除服务器权限问题(zip文件可解压成功,程序正常运行) 2、排除RAR解压命令问题(压缩包已经正常解压) 3、那现在就只剩下代码问题了 由于系统是接手的项目,工具类在别的代码中也有引用,就直接拿过来使用,理所当然的认为代码没问题,于是开始找自己的问题(服务器目录权限、服务器上RAR版本等都没找到),准备在服务器上生成程序的dump日志,在查看服务器进程时发现了新大陆,如下图: ![在这里插入图片描述](https://img-blog.csdnimg.cn/2021060213295942.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1aGFuY2hlbm1pbg==,size_16,color_FFFFFF,t_70#pic_center)

这个是解压RAR文件的进程,那问题可以确定了,也就是RAR解压没有关掉进程,那我看下JAVA执行linux命令形式:

Process proc = Runtime.getRuntime().exec(cmd)

百度下Process在线API:
重点我们看下边的图:
听到这儿马起来对比代码:
这个缺乏了杀害子进程的代码,那我们把代码更改下,下边是ZIP和RAR解压的工具类:

import cn.hutool.core.io.FileUtil; import lombok.extern.slf4j.Slf4j; import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipFile; import java.io.*; import java.util.Enumeration; @Slf4j public class ZipAndRarTools { public static void unZip(String zipFileName, String descFileName, boolean isDel) throws IOException { System.out.println("文件解压开始..."); String descFileNames = descFileName; if (!descFileNames.endsWith(File.separator)) { descFileNames = descFileNames + File.separator; } ZipFile zipFile = null; try { zipFile = new ZipFile(zipFileName); ZipEntry entry = null; String entryName = null; String descFileDir = null; byte[] buf = new byte[4096]; int readByte = 0; @SuppressWarnings("rawtypes") Enumeration enums = zipFile.getEntries(); while (enums.hasMoreElements()) { entry = (ZipEntry) enums.nextElement(); entryName = entry.getName(); descFileDir = descFileNames + entryName; if (entry.isDirectory()) { new File(descFileDir).mkdir(); continue; } else { new File(descFileDir).getParentFile().mkdir(); } File file = new File(descFileDir); OutputStream os = new FileOutputStream(file); InputStream is = zipFile.getInputStream(entry); while ((readByte = is.read(buf)) != -1) { os.write(buf, 0, readByte); } os.close(); is.close(); } System.out.println("文件解压成功!"); } catch (Exception e) { System.out.println("文件解压失败!"); e.printStackTrace(); } finally { zipFile.close(); } //删除压缩包 if (isDel) { FileUtil.del(zipFileName); } } public static boolean realExtract(String zipFile, String destDir) { // 解决路径中存在/..格式的路径问题 destDir = new File(destDir).getAbsoluteFile().getAbsolutePath(); while (destDir.contains("..")) { String[] sepList = destDir.split("\\"); destDir = ""; for (int i = 0; i < sepList.length; i++) { if (!"..".equals(sepList[i]) && i < sepList.length - 1 && "..".equals(sepList[i + 1])) { i++; } else { destDir += sepList[i] + File.separator; } } } boolean bool = false; if (!FileUtil.exist(zipFile)) { return false; } if (!FileUtil.exist(destDir)) { FileUtil.mkdir(destDir); } //判断系统类型 开始调用命令行解压,参数-o+是表示覆盖的意思 String cmdPath = ""; String osName = System.getProperty("os.name"); if (osName.contains("Window")) { cmdPath = "C:\Program Files\WinRAR\WinRAR.exe"; } else { cmdPath = "/usr/local/bin/unrar"; } String cmd = cmdPath + " X -o+ " + zipFile + " " + destDir; System.out.println(cmd); try { File file = new File(zipFile); String s; Process proc = Runtime.getRuntime().exec(cmd); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(proc.getInputStream())); while((s = bufferedReader.readLine()) != null) { // 输出解压日志 log.info(file.getName() + "-->" + s); } if (proc.waitFor() != 0) { if (proc.exitValue() == 0) { bool = false; } } else { bool = true; } // 关闭进程 proc.destroy(); } catch (Exception e) { log.error("解压失败:" + e.getMessage(), e); e.printStackTrace(); } System.out.println("解压" + (bool ? "成功" : "失败")); return bool; } }

问题解决收工,记录问题希望能帮到你们linux内存管理,如有错误请强调,感谢