相关文章推荐

在工作中,开发了一个文件上传的接口,然后开发自测的时候没出现问题,自己搞了个40M的视频上传,需求要求的是最大可接收1G,于是找了个海绵宝宝第678集1.2G在本地服务上传;
于是测试完成上传到线上(这里我反思不应该在本地服务测试应该发到测试环境,当时偷懒);
结果线上上传一个400M的视频就导致OOM;
我说不应该呀,我本地咋不会出现OOM,是不是线上内存太小了,上阿里云K8s上一看配置参数:内存才600M;继续疑惑那400M的视频也不至于导致内存溢出吧;

二.解决问题

于是读代码:
工具类代码:

public static ByteArrayOutputStream inputToByteArrayOutPut(InputStream input) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        try {
            while ((len = input.read(buffer)) > -1) {
                baos.write(buffer, 0, len);
            baos.flush();
        } catch (IOException e) {
            throw new Exception("Illegal flow.");
        } finally {
            try {
                input.close();
            } catch (IOException e) {
                log.error("file stream shutdown failed.");
        return baos;

这个方法就是 inputToByteArrayOutPut 将一个输入流(InputStream)的内容读入到一个字节数组输出流(ByteArrayOutputStream)中,然后返回输出流;平平无奇
继续深入底层 读源码: ByteArrayOutputStream的.write方法

public synchronized void write(byte b[], int off, int len) {
        if ((off < 0) || (off > b.length) || (len < 0) ||
            ((off + len) - b.length > 0)) {
            throw new IndexOutOfBoundsException();
        ensureCapacity(count + len);
        System.arraycopy(b, off, buf, count, len);
        count += len;

这个 write 方法是一个用于将字节数组的一部分写入缓冲区的同步方法。它首先进行边界检查,确保参数合法,然后调用 ensureCapacity 方法确保缓冲区有足够的空间,最后使用 System.arraycopy 将字节数组的内容复制到缓冲区中,然后更新计数器 count;
继续-read源码: ensureCapacity()方法

private void ensureCapacity(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - buf.length > 0)
            grow(minCapacity);

从这里看如果复制的容量大于缓冲区容量就调用扩容方法
grow(minCapacity)

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = buf.length;//获取当前数组的容量 作为 旧容量 (oldCapacity);
        int newCapacity = oldCapacity << 1; //将旧容量左移一位(即乘以2),得到新容量
        if (newCapacity - minCapacity < 0)  //检查新容量是否小于最小需求容量 (minCapacity
            newCapacity = minCapacity;//如果新容量小于最小需求容量,则将新容量设置为最小需求容量,以确保至少能容纳 minCapacity 个元素。
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        buf = Arrays.copyOf(buf, newCapacity);

问题在这里就出现了

int newCapacity = oldCapacity << 1; //将旧容量左移一位(即乘以2),得到新容量

每次扩容数组都是以旧容量的两倍扩容

这就会导致可能视频在300M~400M复制的时候就触发了扩容,导致OOM

而我本地是设置了2048M的内存,所以之前测试都没有问题

解决方法:1.根据视频大小提前设置缓冲池大小 2.扩大线上内存至2048M

以前的上传代码中使用了 URL url = new **URL**(urlStr); conn = (HttpURLConnection) url.openConnection(); ....省略 out = conn.getOutputStream(); conn.setRequestMethod("POST"); conn.con... * 使用字节数组输出流中的字节数组作为正文内容 * java.io.ByteArrayOutputStream是一个低级流,其内部维护一个字节数组 * 通过这个流写出的数据全部存入该数组中 private ByteArrayOutputStream baos; private byte[] contentData;//保存动态数据的(数据从baos里获取的) * 响应发送前的准备工作 private void sendBefore() { if (bao.
Java ByteArrayOutputStream类 字节数组输出流在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组缓冲区中。创建字节数组输出流对象有以下几种方式。 下面的构造方法创建一个32字节(默认大小)的缓冲区。 OutputStream bOut = new ByteArrayOutputStream(); 另一个构造方法创建一个大小为n字节的
@Test public void testByteArrayIO() throws IOException{ ByteArrayOutputStream buf=new ByteArrayOutputStream();//节点流,实际上是内存中长度可变的数组,低级流 buf.write(5); buf.write(6); buf.close(); byte[] bytes=
原作者:Mr.S 版权声明:本文版权归微信公众号玉刚说所有,未经许可,不得以任何形式转载 原文链接:https://juejin.im/post/5b50b017f265da0f7b2f649c 什么是性能 快,稳,省,小,这四点很形象的代表了性能的四个方面,同时也让我们知道我们App现在是否是款性能良好的APP,如果有一项不达标,那么说明我们的应用有待优化。 很多时候我们注重功能实现,保证能用,但是我们会发现,这样的应用很难拿的出手,里面的槽点太多了,性能很差,但是 //用内存,将小写字母替换成大写字母 String str = "helloworld,goodmorning"; ByteArrayOutputStream bos = null; ByteArrayInputStream bis = null; bis = new ByteArrayInputStream(str.getBytes());     ByteArrayInputStream是字节数组输入流,在内存中创建了一个字节数组,将输入流中读取的数据保存到字节数组的缓存区中.也就是说字节数组输入流将读取数据放到字节数组缓冲区中.     1.ByteArrayInputStream构造方法有两个: public ByteArrayInputStream(byte buf[]) {} public ByteArrayI...
 
推荐文章