深入理解JVM - 内存溢出实战

Java堆溢出

Java堆用于存储对象实例,只要不断地创建对象,当对象数量到达最大堆的容量限制后就会产生内存溢出异常。最常见的内存溢出就是存在大的容器,而没法回收,比如:Map,List等。

出现下面信息就可以断定出现了堆内存溢出。

java.lang.OutOfMemoryError: Java heap space

保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象

示例
设置JVM内存参数:

-verbose:gc -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
/**
 * java 堆内存溢出
 * <p>
 * VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
 *
 * @author yuhao.wang3
 * @since 2019/11/30 17:09
 */
public class HeapOutOfMemoryErrorTest {
    public static void main(String[] args) throws InterruptedException {
        // 模拟大容器
        List<Object> list = Lists.newArrayList();
        for (long i = 1; i > 0; i++) {
            list.add(new Object());
            if (i % 100_000 == 0) {
                System.out.println(Thread.currentThread().getName() + "::" + i);
            }
        }
    }
}

运行结果

[GC (Allocation Failure)  5596K->1589K(19968K), 0.0422027 secs]
main::100000
main::200000
[GC (Allocation Failure)  7221K->5476K(19968K), 0.0144103 secs]
main::300000
[GC (Allocation Failure)  9190K->9195K(19968K), 0.0098252 secs]
main::400000
main::500000
[Full GC (Ergonomics)  17992K->13471K(19968K), 0.3431052 secs]
main::600000
main::700000
main::800000
[Full GC (Ergonomics)  17127K->16788K(19968K), 0.1581969 secs]
[Full GC (Allocation Failure)  16788K->16758K(19968K), 0.1994445 secs]
java.lang.OutOfMemoryError: Java heap space
Dumping heap to D:\dump\java_pid7432.hprof ...
Heap dump file created [28774262 bytes in 0.221 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3210)
    at java.util.Arrays.copyOf(Arrays.java:3181)
    at java.util.ArrayList.grow(ArrayList.java:261)
    at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
    at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
    at java.util.ArrayList.add(ArrayList.java:458)
    at com.xiaolyuh.HeapOutOfMemoryErrorTest.main(HeapOutOfMemoryErrorTest.java:23)
Disconnected from the target VM, address: '127.0.0.1:61622', transport: 'socket'

分析工具

JDK自带的jvisualvm.exe工具可以分析.hprof和.dump文件。

首先需要找出最大的对象,判断最大对象的存在是否合理,如何合理就需要调整JVM内存大小。如果不合理,那么这个对象的存在,就是最有可能是引起内存溢出的根源。通过GC Roots的引用链信息,就可以比较准确地定位出泄露代码的位置。

  1. 查询最大对象

up-601558c8ddac2e7c92b10debf904ac811b7.png

2.找出具体的对象
up-23d46b99308e12c6a958bd5710b148cc28b.png

解决方案

1.优化代码,去除大对象;
2.调整JVM内存大小(-Xmx与-Xms);

超出GC开销限制

当出现java.lang.OutOfMemoryError: GC overhead limit exceeded异常信息时,表示超出了GC开销限制。当超过98%的时间用来做GC,但是却回收了不到2%的堆内存时会抛出此异常。

异常栈

[Full GC (Ergonomics)  19225K->19225K(19968K), 0.1044070 secs]
[Full GC (Ergonomics)  19227K->19227K(19968K), 0.0684710 secs]
java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to D:\dump\java_pid17556.hprof ...
Heap dump file created [34925385 bytes in 0.132 secs]
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
[Full GC (Ergonomics)  19257K->933K(19968K), 0.0403569 secs]
    at com.xiaolyuh.HeapOutOfMemoryErrorTest.main(HeapOutOfMemoryErrorTest.java:25)
ERROR: JDWP Unable to get JNI 1.2 environment, jvm->GetEnv() return code = -2
JDWP exit error AGENT_ERROR_NO_JNI_ENV(183):  [util.c:840]

解决方案

1.通过-XX:-UseGCOverheadLimit参数来禁用这个检查,但是并不能从根本上来解决内存溢出的问题,最后还是会报出java.lang.OutOfMemoryError: Java heap space异常;
2.调整JVM内存大小(-Xmx与-Xms);

虚拟机栈和本地方法栈溢出

  • 如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
  • 如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。

这里把异常分成两种情况,看似更加严谨,但却存在着一些互相重叠的地方:当栈空间无法继续分配时,到底是内存太小,还是已使用的栈空间太大,其本质上只是对同一件事情的两种描述而已。

StackOverflowError

出现StackOverflowError异常的主要原因有两点:

  • 单个线程请求的栈深度大于虚拟机所允许的最大深度
  • 创建的线程过多

单个线程请求的栈深度过大

单个线程请求的栈深度大于虚拟机所允许的最大深度,主要表现有以下几点:

  1. 存在递归调用
  2. 存在循环依赖调用
  3. 方法调用链路很深,比如使用装饰器模式的时候,对已经装饰后的对象再进行装饰

异常信息java.lang.StackOverflowError。

装饰器示例:

Collections.unmodifiableList(
        Collections.unmodifiableList(
                Collections.unmodifiableList(
                        Collections.unmodifiableList(
                                Collections.unmodifiableList(
                                                        ...)))))));                                           

递归示例:

/**
 * java 虚拟机栈和本地方法栈内存溢出测试
 * <p>
 * VM Args: -Xss128k
 *
 * @author yuhao.wang3
 * @since 2019/11/30 17:09
 */
public class StackOverflowErrorErrorTest {
    private int stackLength = 0;

    public void stackLeak() {
        stackLength++;
        stackLeak();
    }

    public static void main(String[] args) {
        StackOverflowErrorErrorTest sof = new StackOverflowErrorErrorTest();
        try {
            sof.stackLeak();
        } catch (Exception e) {
            System.out.println(sof.stackLength);
            e.printStackTrace();
        }
    }
}

运行结果:

stackLength::1372
java.lang.StackOverflowError
    at com.xiaolyuh.StackOverflowErrorErrorTest.stackLeak(StackOverflowErrorErrorTest.java:16)
    at com.xiaolyuh.StackOverflowErrorErrorTest.stackLeak(StackOverflowErrorErrorTest.java:16)
    at com.xiaolyuh.StackOverflowErrorErrorTest.stackLeak(StackOverflowErrorErrorTest.java:16)
...

当增大栈空间的时候我们就会发现,递归深度会增加,修改栈空间-Xss1m,然后运行程序,运行结果如下:

stackLength::20641
java.lang.StackOverflowError
    at com.xiaolyuh.StackOverflowErrorErrorTest.stackLeak(StackOverflowErrorErrorTest.java:16)
    at com.xiaolyuh.StackOverflowErrorErrorTest.stackLeak(StackOverflowErrorErrorTest.java:16)
...

修改递归方法的参数列表后递归深度急剧减少:

public void stackLeak(String ags1, String ags2, String ags3) {
    stackLength++;
    stackLeak(ags1, ags2, ags3);
}

运行结果如下:

stackLength::13154
java.lang.StackOverflowError
    at com.xiaolyuh.StackOverflowErrorErrorTest.stackLeak(StackOverflowErrorErrorTest.java:16)
    at com.xiaolyuh.StackOverflowErrorErrorTest.stackLeak(StackOverflowErrorErrorTest.java:16)
...

由此可见影响递归的深度因素有:

  1. 单个线程的栈空间大小(-Xss)
  2. 局部变量表的大小
单个线程请求的栈深度超过内存限制导致的栈内存溢出,一般是由于非正确的编码导致的。从上面的示例我们可以看出,当栈空间在-Xss128k的时候,调用层级都在1000以上,一般情况下方法的调用是达不到这个深度的。如果方法调用的深度确实有这么大,那么我们可以通过-Xss配置来增大栈空间大小。

创建的线程过多

不断地建立线程也可能导致栈内存溢出,因为我们机器的总内存是有限制的,所以虚拟机栈和本地方法栈对应的内存也是有最大限制的。如果单个线程的栈空间越大,那么整个应用允许创建的线程数就越少。异常信息java.lang.OutOfMemoryError: unable to create new native thread。

虚拟机栈和本地方法栈内存 ≈ 操作系统内存限制 - 最大堆容量(Xmx) - 最大方法区容量(MaxPermSize)
过多创建线程示例:

/**
 * java 虚拟机栈和本地方法栈内存溢出测试
 * <p>
 * 创建线程过多导致内存溢出异常
 * <p>
 * VM Args: -verbose:gc -Xss20M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
 *
 * @author yuhao.wang3
 * @since 2019/11/30 17:09
 */
public class StackOutOfMemoryErrorTest {
    private static int threadCount;

    public static void main(String[] args) throws Throwable {
        try {
            while (true) {
                threadCount++;
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(1000 * 60 * 10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        } catch (Throwable e) {
            e.printStackTrace();
            throw e;
        } finally {
            System.out.println("threadCount=" + threadCount);
        }
    }
}

Java的线程是映射到操作系统的内核线程上,因此上述代码执行时有较大的风险,可能会导致操作系统假死。

运行结果:

java.lang.OutOfMemoryError: unable to create new native thread
    at java.lang.Thread.start0(Native Method)
    at java.lang.Thread.start(Thread.java:717)
    at StackOutOfMemoryErrorTest.main(StackOutOfMemoryErrorTest.java:17)
threadCount=4131
Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread
    at java.lang.Thread.start0(Native Method)
    at java.lang.Thread.start(Thread.java:717)
    at StackOutOfMemoryErrorTest.main(StackOutOfMemoryErrorTest.java:17)

需要重新上述异常,最好是在32位机器上,因为我在64位机器没有重现。

在有限的内存空间里面,当我们需要创建更多的线程的时候,我们可以减少单个线程的栈空间大小。

元数据区域的内存溢出
元数据区域或方法区是用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。我们可以通过在运行时产生大量的类去填满方法区,直到溢出,如:代理的使用(CGlib)、大量JSP或动态产生JSP文件的应用(JSP第一次运行时需要编译为Java类)、基于OSGi的应用(即使是同一个类文件,被不同的加载器加载也会视为不同的类)等。

/**
 * java 元数据区域/方法区的内存溢出
 * <p>
 * VM Args JDK 1.6: set JAVA_OPTS=-verbose:gc -XX:PermSize=10m -XX:MaxPermSize=10m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
 * <p>
 * VM Args JDK 1.8: set JAVA_OPTS=-verbose:gc -Xmx20m -XX:MetaspaceSize=5m -XX:MaxMetaspaceSize=5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
 *
 * @author yuhao.wang3
 * @since 2019/11/30 17:09
 */
public class MethodAreaOutOfMemoryErrorTest {

    static class MethodAreaOOM {
    }

    public static void main(String[] args) {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(MethodAreaOOM.class);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object obj, Method method, Object[] params, MethodProxy proxy) throws Throwable {
                    return proxy.invokeSuper(obj, params);
                }
            });
            enhancer.create();
        }
    }
}

运行结果:

[GC (Last ditch collection)  1283K->1283K(16384K), 0.0002585 secs]
[Full GC (Last ditch collection)  1283K->1226K(19968K), 0.0075856 secs]
java.lang.OutOfMemoryError: Metaspace
Dumping heap to D:\dump\java_pid18364.hprof ...
Heap dump file created [2479477 bytes in 0.015 secs]
[GC (Metadata GC Threshold)  1450K->1354K(19968K), 0.0003906 secs]
[Full GC (Metadata GC Threshold)  1354K->976K(19968K), 0.0073752 secs]
[GC (Last ditch collection)  976K->976K(19968K), 0.0002921 secs]
[Full GC (Last ditch collection)  976K->973K(19968K), 0.0045243 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Metaspace
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:52)
    at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:116)
    at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:291)
    at org.springframework.cglib.core.KeyFactory$Generator.create(KeyFactory.java:221)
    at org.springframework.cglib.core.KeyFactory.create(KeyFactory.java:174)
    at org.springframework.cglib.core.KeyFactory.create(KeyFactory.java:153)
    at org.springframework.cglib.proxy.Enhancer.<clinit>(Enhancer.java:73)
    at com.xiaolyuh.MethodAreaOutOfMemoryErrorTest.main(MethodAreaOutOfMemoryErrorTest.java:26)

运行时常量池的内存溢出
String.intern()是一个Native方法,它的作用是:如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。

在JDK 1.6的时候,运行时常量池是在方法区中,所以直接限制了方法区中大小就可以模拟出运行池常量池的内存溢出。

/**
 * java 方法区和运行时常量池溢出
 * <p>
 * VM Args JDK 1.6: set JAVA_OPTS=-verbose:gc -XX:PermSize10 -XX:MaxPermSize10m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
 *
 * @author yuhao.wang3
 * @since 2019/11/30 17:09
 */
public class RuntimeConstantOutOfMemoryErrorTest {

    public static void main(String[] args) {
        // 使用List保存着常量池的引用,避免Full GC 回收常量池行为
        List<String> list = new ArrayList<>();
        for (int i = 0; ; i++) {
            list.add(String.valueOf(i).intern());
        }
    }
}

运行结果:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
    at java.lang.String.intern(Native Method)
    at RuntimeConstantOutOfMemoryErrorTest.main(RuntimeConstantOutOfMemoryErrorTest.java:18)

直接内存溢出

DirectMemory容量可通过-XX:MaxDirectMemorySize指定,如果不指定,则默认与Java堆最大值(-Xmx指定)一样。

/**
 * java 直接内存溢出
 * <p>
 * VM Args JDK 1.6: set JAVA_OPTS=-verbose:gc -Xms20m -XX:MaxDirectMemorySize=10m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\dump
 *
 * @author yuhao.wang3
 * @since 2019/11/30 17:09
 */
public class DirectMemoryOutOfMemoryErrorTest {

    public static void main(String[] args) throws IllegalAccessException {
        int _1M = 1024 * 1024;
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while (true) {
            unsafe.allocateMemory(_1M);
        }
    }
}

运行结果:

Exception in thread "main" java.lang.OutOfMemoryError
    at sun.misc.Unsafe.allocateMemory(Native Method)
    at com.xiaolyuh.DirectMemoryOutOfMemoryErrorTest.main(DirectMemoryOutOfMemoryErrorTest.java:23)

由DirectMemory导致的内存溢出,一个明显的特征是在Heap Dump文件中不会看见明显的异常,如果读者发现OOM之后Dump文件很小,而程序中又直接或间接使用了NIO,那就可以考虑检查一下是不是这方面的原因。

解决方案

通过-XX:MaxDirectMemorySize指定直接内存大小。

源码

https://github.com/wyh-spring...

spring-boot-student-jvm工程

Image placeholder
Just_on_it
未设置
  66人点赞

没有讨论,发表一下自己的看法吧

推荐文章
JVM内存布局

   JVM中将内存分为若干部分:堆、方法区、虚拟机栈、本地方法栈、程序计数器             程序计数器:该区域是内存中较小的一块区域---是当前线程在执行的字节码的行号指示器。程序计数器是

深入了解JavaScript async/await !

Asyncfunctions让我们以async这个关键字开始。它可以被放置在任何函数前面,像下面这样:asyncfunctionf(){ return1; }在函数前面的「async」这个单词表达了一

JVM是怎么和操作系统交互的?

来源:阿里巴巴中间件肉眼看计算机是由CPU、内存、显示器这些硬件设备组成,但大部分人从事的是软件开发工作。计算机底层原理就是连通硬件和软件的桥梁,理解计算机底层原理才能在程序设计这条路上越走越快,越走

记一次JVM FullGC引发严重线上事故的定位、分析、解决过程!

这篇文章给大家聊一次线上生产系统事故的解决经历,其背后代表的是线上生产系统的JVMFullGC可能引发的严重故障。一、业务场景介绍先简单说说线上生产系统的一个背景,因为仅仅是文章作为案例来讲,所以弱化

记一次隐藏很深的 JVM 线上惨案的分析、排查、解决!

1、本文背景本文会给大家讲解一个比较特殊的JVM优化案例,这个优化案例本身是因为新手工程师对JVM优化可能了解了一个半吊子,然后不知道从哪里找来了一个非常特殊的JVM参数错误的设置了一下,就导致线上系

JVM CPU Profiler技术原理及源码深度解析

本文介绍了JVM平台上CPUProfiler的实现原理,希望能帮助读者在使用类似工具的同时也能清楚其内部的技术实现。引言研发人员在遇到线上报警或需要优化系统性能时,常常需要分析程序运行行为和性能瓶颈。

老司机带你深入理解 Laravel 之 Facade

前言 时间真的过的很快啊,今天都2019年12月2号了,准确的说,写这篇博客的时间是晚上21点40分,刚从公司加班回来,洗完澡就坐下来写这篇文章了,不知不觉除这篇博客外,我已经写了11篇了,要讲的东西

深入理解 MySQL—锁、事务与并发控制

本文对MySQL数据库中有关锁、事务及并发控制的知识及其原理做了系统化的介绍和总结,希望帮助读者能更加深刻地理解MySQL中的锁和事务,从而在业务系统开发过程中可以更好地优化与数据库的交互。1.MyS

阿里大佬带你,深入理解线程池底层原理

为什么要使用线程池在实际使用中,线程是很占用系统资源的,如果对线程管理不善很容易导致系统问题。因此,在大多数并发框架中都会使用线程池来管理线程,使用线程池管理线程主要有如下好处:(1)降低资源消耗。通

Java并发编程,深入理解ReentrantLock

ReentrantLock简介ReentrantLock重入锁, 是实现Lock接口的一个类 ,也是在实际编程中使用频率很高的一个锁,支持重入性,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次

VMware斥资27亿美元完成对Pivotal的收购

昨日,VMware公司正式宣布,已经完成对Pivotal公司的收购,这笔交易斥资27亿美元。收购完成后,Pivotal的股权结构将从纽约证券交易所退市,以VMware全资子公司的形式运营。其实,VMw

react是mvvm框架吗?

react是mvvm框架吗?不是。React可以作为MVVM中第二个V,也就是View,但是并不是MVVM框架。MVVM一个最显著的特征:双向绑定。React没有这个,它是单向数据绑定的。React是

MVVM原理(Object.defineProperty和订阅者模式)

想着去了解vue的mvvm数据驱动是怎么实现的,百度中看了这篇文章,demo很好。其他文章只是讲到defineProperty的set,get。彻底理解Vue中的Watcher、Observer、De

记一次 vue 的异步更新队列导致内存泄漏

起因 由于项目是需要连续传输图片形成一个伪视频(没办法,客户钱给的不够)来观看。后端采用传输base64的图片到前端展示。 环境 php:7.2 workerman:3.X vue:2.X 过程 wo

Go语言高级编程_1.5 面向并发的内存模型

1.5面向并发的内存模型 在早期,CPU都是以单核的形式顺序执行机器指令。Go语言的祖先C语言正是这种顺序编程语言的代表。顺序编程语言中的顺序是指:所有的指令都是以串行的方式执行,在相同的时刻有且仅有

Go语言高级编程_2.7 CGO内存模型

2.7CGO内存模型 CGO是架接Go语言和C语言的桥梁,它使二者在二进制接口层面实现了互通,但是我们要注意因两种语言的内存模型的差异而可能引起的问题。如果在CGO处理的跨语言函数调用时涉及到了指针的

基于内存和文件存储的 queue worker, 不用 Redis 适合单进程使用没有外部依赖

因为最近要做一个简单的并发任务系统,在github上面找了一圈并没有简单可依赖的库,所以自己写了一个。欢迎大家Review贡献代码。项目地址https://github.com/iflamed/mfw

Go内存分配跟踪调优

今天小编为大家分享一篇关于Go内存分配跟踪调优的文章,文中涉及到一些压测及跟踪分析的工具,以及问题查找方法,希望能对大家有所帮助。Makeitwork,makeitright,makeitfast.–

共享内存在不同系统的应用与优劣详解

共享内存是一种使计算机程序能够同时共享内存资源以实现更高性能和更少冗余数据副本的技术。共享系统内存可以在单处理器系统、并行多处理器或集群微处理器上运行。对于分布式系统会有一些差异,但共享内存也可以其上

多进程之间的线程利用XSI IPC共享内存分配互斥量进行同步

···#include#include#include#include#include#include#include#include#include#definehandle_error_en(en

自动识别Android不合理的内存分配

写在前面Android开发中我们常常会遇到不合理的内存分配导致的问题,或是频繁GC,或是OOM。按照常规的套路我们需要打开AndroidStudio录制内存分配或者dump内存,然后人工分析,逐个排查

Java内存映射,上G大文件轻松处理

内存映射文件(Memory-mappedFile),指的是将一段虚拟内存逐字节映射于一个文件,使得应用程序处理文件如同访问主内存(但在真正使用到这些数据前却不会消耗物理内存,也不会有读写磁盘的操作),

面试题:请解释一下什么是虚拟内存?

内存对于用户来说就是一个字节数组,我们可以根据地址来访问到某个字节或者某些字节:很久之前的内存很久很久之前,一台机器上只放置一个程序,操作系统仅仅作为一个函数库存在。对于内存来说,除去操作系统的代码和

Kafka 如何优化内存缓冲机制造成的频繁 GC 问题?

目录1、Kafka的客户端缓冲机制2、内存缓冲造成的频繁GC问题3、Kafka设计者实现的缓冲池机制4、总结一下“ 这篇文章,给大家聊一个硬核的技术知识,我们通过Kafka内核源码中的一些设计思想,来

打破边界 不是所有“内存与存储”都叫傲腾

人类正在向一个万物感知、万物互联、万物智能的世界进化。一方面海量的数据对数据基础设施带来了新的挑战;另一方面伴随着数据中心业务和应用的多样化以及智能化,企业对数据存储的需求越来越高。智能世界的特点是能