掘金 后端 ( ) • 2024-04-20 17:54

以下来自本人拉的一个关于 Java 技术的讨论群。关注公众号:hashcon,私信进群拉你

JVM 堆外内存如何查看?

参考:https://juejin.cn/post/7225871227743043644

分为:

  1. 通过 Native Memory Tracking 能看到的:
    1. Java堆内存,所有 Java 对象分配占用内存的来源
    2. 2.元空间,JVM 将类文件加载到内存中用于后续使用占用的空间,注意是 JVM C++ 层面的内存占用,主要包括类文件中在 JVM 解析为 C++ 的 Klass 类以及相关元素。
    3. C++ 字符串即符号(Symbol)占用空间,前面加载类的时候,其实里面有很多字符串信息(注意不是 Java 字符串,是 JVM 层面 C++ 字符串),不同类的字符串信息可能会重复(
    4. 线程占用内存,主要是每个线程的线程栈,我们也只会主要分析线程栈占用空间(在第五章),其他的管理线程占用的空间很小,可以忽略不计。
    5. JIT编译器本身占用的空间以及JIT编译器编译后的代码占用空间
    6. Arena 数据结构占用空间,我们看到 Native Memory Tracking 中有很多通过 arena 分配的内存,这个就是管理 Arena 数据结构占用空间。
    7. JVM Tracing 占用内存,包括 JVM perf 以及 JFR 占用的空间。
    8. 写 JVM 日志占用的内存(-Xlog 参数指定的日志输出,并且 Java 17 之后引入了异步 JVM 日志-Xlog:async,异步日志所需的 buffer 也在这里)
    9. JVM 参数占用内存,我们需要保存并处理当前的 JVM 参数以及用户启动 JVM 的是传入的各种参数(有时候称为 flag)
    10. JVM 安全点占用内存,是固定的两页内存(我这里是一页是 4KB,后面第二章会分析这个页大小与操作系统相关),用于 JVM 安全点的实现,不会随着 JVM 运行时的内存占用而变化。
    11. Java 同步机制(例如 synchronized,还有 AQS 的基础 LockSupport)底层依赖的 C++ 的数据结构,系统内部的 mutex 等占用的内存。
    12. JVM TI 相关内存,JVMTI 是 Java 虚拟机工具接口(Java Virtual Machine Tool Interface)的缩写。它是 Java 虚拟机(JVM)的一部分,提供了一组 API,使开发人员可以开发自己的 Java 工具和代理程序,以监视、分析和调试 Java 应用程序。JVMTI API 是一组 C/C++ 函数,可以通过 JVM TI Agent Library 和 JVM 进行交互。开发人员可以使用 JVMTI API 开发自己的 JVM 代理程序或工具,以监视和操作 Java 应用程序。
    13. Java 字符串去重占用内存:Java 字符串去重机制可以减少应用程序中字符串对象的内存占用。 在 Java 应用程序中,字符串常量是不可变的,并且通常被使用多次。这意味着在应用程序中可能存在大量相同的字符串对象,这些对象占用了大量的内存。Java 字符串去重机制通过在堆中共享相同的字符串对象来解决这个问题。当一个字符串对象被创建时,JVM 会检查堆中是否已经存在相同的字符串对象。如果存在,那么新的字符串对象将被舍弃,而引用被返回给现有的对象。这样就可以减少应用程序中字符串对象的数量,从而减少内存占用。 但是这个机制一直在某些 GC 下表现不佳,尤其是 G1GC 以及 ZGC 中,所以默认是关闭的,可以通过 -XX:+UseStringDeduplication 来启用。
    14. JVM GC需要的数据结构与记录信息占用的空间,这块内存可能会比较大,尤其是对于那种专注于低延迟的 GC,例如 ZGC。其实 ZGC 是一种以空间换时间的思路,提高 CPU 消耗与内存占用,但是消灭全局暂停。之后的 ZGC 优化方向就是尽量降低 CPU 消耗与内存占用,相当于提高了性价比。
    15. JVM内部(不属于其他类的占用就会归到这一类)与其他占用(不是 JVM 本身而是操作系统的某些系统调用导致额外占的空间),不会很大。但是这里会因为某些 bug 导致很大,例如:
      1. https://bugs.openjdk.org/browse/JDK-8305994 。 Java 15,16 引入的 bug,17 低版本存在这个问题,21 修复的,在 17.0.8 port 回 17 的。
  2. 开启 Native Memory Tracking 本身消耗的内存
  3. 通过 Native Memory Tracking 看不到的:
    1. DirectBuffer:通过 ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024); 分配的,底层基于 JNI + 系统调用,不会被 Native Memory Tracking 采集
    2. MMAP Buufer:通过 MappedByteBuffer mmap = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, fileChannel.size()); 分配的,底层基于 JNI + 系统调用,不会被 Native Memory Tracking 采集

目前,Native Memory Tracking 已经可以通过 JFR 查看(Java 22):

image image

查看 Native Memory Tracking 看不到的 Direct Buffer 以及 MMAP Buffer 的方式,可以通过 JMX 查看,这里给一个 Jconsole 的截图,大家通过截图的这个路径写代码访问 MBean 就能看到:

image

个人简介:个人业余研究了 AI LLM 微调与 RAG,目前成果是微调了三个模型:

  1. 一个模型是基于 whisper 模型的微调,使用我原来做的精翻的视频按照语句段落切分的片段,并尝试按照方言类别,以及技术类别分别尝试微调的成果。用于视频字幕识别。
  2. 一个模型是基于 Mistral Large 的模型的微调,识别提取视频课件的片段,辅以实际的课件文字进行识别微调。用于识别课件的片段。
  3. 最后一个模型是基于 Claude 3 的模型微调,使用我之前制作的翻译字幕,与 AWS、Go 社区、CNCF 生态里面的官方英文文档以及中文文档作为语料,按照内容段交叉拆分,进行微调,用于字幕翻译。

目前,准确率已经非常高了。大家如果有想要我制作的视频,欢迎关注留言。

本人也是开源代码爱好者,贡献过很多项目的源码(Mycat 和 Java JFRUnit 的核心贡献者,贡献过 OpenJDK,Spring,Spring Cloud,Apache Bookkeeper,Apache RocketMQ,Ribbon,Lettuce、 SocketIO、Langchain4j 等项目 ),同时也是深度技术迷,编写过很多硬核的原理分析系列(JVM)。本人也有一个 Java 技术交流群,感兴趣的欢迎关注。

另外,一如即往的是,全网的所有收益,都会捐赠给希望工程,坚持靠爱与兴趣发电。