同事反映30MB的文件预览不了, 让我帮忙看下.
直接通过异常堆栈找到对应的方法. 大概实现是:
GridFSFile dbFile = gridFsTemplate.findOne(query);GridFSDownloadStream gridFSDownloadStream = gridFSBucket.openDownloadStream(dbFile.getObjectId());GridFsResource resource = new GridFsResource(dbFile, gridFSDownloadStream);bufferedInputStream = new BufferedInputStream(resource.getInputStream());String fileType = fileName.substring(fileName.lastIndexOf("."));paramMap.put("bytes", Base64.encode(bufferedInputStream.readAllBytes()));String response = HttpUtil.post(previewServUrl, JSONUtil.toJsonStr(JSONUtil.parse(paramMap)), timeOut);
上profile:
真是令人心脏骤停, 30MB能膨胀到4GB, 把消耗最高的JsonUtil换成jackson:
降到200MB了, 但是还不太够, 测试环境的实例只分配了1g内存, 光开着这程序就用了800多MB了.
接下来从Base64.encode(bufferedInputStream.readAllBytes()
下手, profile显示它消耗了200MB.
通过idea提供的跳转功能, 具体造成消耗的是readAllBytes
这个方法.
接下来修改读取的文件流, 考虑到上传的文件不会支持太大, 直接给他一次性预分配和文件一样大的缓冲区:
var w = new byte[(int) Math.min(30 * 1024 * 1024, dbFile.getLength() + 4096)];var bo = new ByteArrayOutputStream(w.length);int bytesRead;while ((bytesRead = gridFSDownloadStream.read(w)) != -1) {bo.write(w, 0, bytesRead);if (bytesRead < w.length) {break;}}paramMap.put("bytes", Base64.encode(bo.toByteArray()));
很好, 降到85MB了, 这段代码已经算是满足需求了, 就不继续了