教你JVM怎么使用native memory

目录
  • JRE如何使用native存储
  • Java堆和GC
    • The Just-in-time (JIT) compiler
    • Classes and classloaders
    • JNI
    • NIO
    • Threads

JRE如何使用native存储

今天看到一篇特别好的文章,翻译其中一小段Understanding how the JVM uses native memory

Runtime环境提供了被某些未知的用户代码驱动的能力,这使runtime在任何情况下都能使用合适的资源。每一个JVM管理的java应用的行为都会潜在的影响JVM所能提供的运行时环境。这一节我们讨论为什么Java应用会消耗native存储

Java堆和GC

Java的堆是用来存储分配对象的一块内存,大多数的JVM有一块逻辑堆内存,也有少数的JVM实现了多块堆存储。一个物理内存可以基于GC被分配成多块逻辑上的内存。

The Just-in-time (JIT) compiler

JIT编译器会把java字节码编译成运行时可以直接运行的机器码,这极大的提升了JRE运行速度,使Java代码运行比肩native code。
字节码编译会使用native内存(同理,一些像GCC这样的编译器也需要内存去run),但是JIT的输入(字节码)输出(机器码)都必须存储在native内存中。所以包含很多JIT-compiled的方法的应用相对来说更占用native内存。

Classes and classloaders

Java程序由定义了对象和方法逻辑的类组成,可能是Java运行时的库(比如java.lang.String),也可能是三方库。这些class在被使用的时候会被加载进来并被存储在内存里面。

class如何被存储不同JVM的实现相差极大。Sun JDK存储在永生带(PermGen),IBM从Java5开始为每个classloader开辟native内存并将它们存储在那里。具体的存储位置需要查看实现的文档。

显而易见的是,用更多的类会消耗更多的内存。(这意味着你的native内存消耗会持续增加,或者明确的开辟一块内存,像PermGen,去容纳所有的class),需要注意的是不止是你的应用的class需要存储,frameworks,application servers,三方库,JRE这里面的class在被用到的时候都会被加载并存储进来。

JRE允许卸载class去回收空间,但是这仅仅是在内存严重不足的情况下。不可能仅仅卸载一个单独的class文件,而是卸载classloader,和它加载进来的所有class,一个classloader仅仅会在以下情况下被卸载:

  • Java堆中不包含任何代表此classloader的java.lang.ClassLoader对象的应引用
  • Java堆中不包含任何代表由此classloader加载进来的类的java.lang.Class对象的引用
  • Java堆中没有任何被此classloader加载进来的对象存活。

JNI

JNI允许本地代码和java代码相互调用。JRE严重依赖JNI代码去实现文件和网络这些类库的功能,一个JNI应用能以三种方式增加JRE的native内存

  • JNI应用的native代码会被编译进一个so动态链接库,运行时会被加载到可执行的地址空间呢,大型native应用程序只需加载就可占据进程地址空间的很大一部分。
  • native代码必须跟JVM共享内存,任何native代码分配或者映射所需要的native内存都需要占用JVM的内存。
  • 某些JNI方法可以使用native作为他们正常操作的一部分,比如GetTypeArrayElements或者GetTypeArrayRegion方法都可以拷贝Java堆内存到到native内存供native代码使用。以这种方式访问大块的Java堆内存相应的会占用大量的native内存

NIO

NIO是java1.4之后添加的API,基于管道和缓存,以一种新的方式实现IO操作。除了基于堆的I/O,NIO还添加了基于native内存的direct ByteBuffer(通过java.nio.ByteBuffer.allocateDirect()方法分配)。Direct ByteBuffers可以直接调用系统库的方法去实现I/O操作,这会显示提升在某些场景下的执行效率,因为能避免在Java堆和native堆之间拷贝数据。

我们可能会疑惑direct ByteBuffer申请的内存到底存在哪里,应用仍然用的是Java堆里面的对象去完成I/O操作,但是持有数据的缓存仍然存在native内存中 -Java堆的对象只是持有了一个native堆缓存的引用。一个non-direct ByteBuffer则是直接在Java堆中存储了byte[]数组。

Memory topology for direct and non-direct java.nio.ByteBuffers

Java堆发生GC的时候同样会对Direct ByteBuffer数据执行清除native缓存操作,GC仅仅会在Java堆中已经满了,不支持新的堆空间分配或者程序手动调用GC(不建议手动调用GC)的情况下发生。

还有一种情况,native内存已经满了,又有代码来请求native内存,但是这个时候Java堆还没有达到GC的条件,所以并不会发生GC。(也就是说native内存的GC完全依赖Java堆的GC,反之如果native需要GC了但是堆没有GC的需求的则不会引发GC)

Threads

应用的每一个线程都需要内存去储存它的栈(这块内存用来存储本地变量表和保存状态),每一个Java线程都需要栈去执行,根据实现,Java线程可以具有单独的native和Java栈。除了堆栈空间之外,每个线程还需要一些native内存用于thread-local存储和内部数据结构。
堆栈大小因Java实现和架构而异。某些实现允许您指定Java线程的堆栈大小。通常在256KB和756KB之间的值。

尽管每个线程使用的内存量非常小,但对于具有数百个线程的应用程序,线程堆栈的总内存使用量可能很大。运行具有比可用处理器多的线程来运行它们的应用程序通常是低效的,并且可能导致性能低下以及增加的内存使用。

以上就是教你JVM怎么使用native memory的详细内容,更多关于JVM使用native memory的资料请关注我们其它相关文章!

(0)

相关推荐

  • 你知道JVM中GC Root对象有哪些吗

    目录 JVM中GC Root对象有哪些 (一)虚拟机栈中引用的对象 (二)方法区中类静态属性引用的对象 (三)方法区中常量引用的对象 (四)本地方法栈中引用的对象 JVM 中的 GC Roots 和可达链 什么是GC Root 对象? 常用的GC算法 GC Root 对象有哪些? 总结 JVM中GC Root对象有哪些 众所周知,我们目前最常用的虚拟机hotspot使用可达性分析来进行垃圾回收,而可达性分析需要依赖GC Root. 下面我就来介绍下可以作为GC Root的对象. (一)虚拟机栈中

  • JVM类加载器之ClassLoader的使用详解

    目录 类加载器 概述 加载器的种类 验证不同加载器 核心方法 JVM类加载机制的三种方式 全盘负责 父类委托.双亲委派 缓存机制 打破双亲委派 重写loadclass方法 自定义类加载器 准备字节码文件 创建自定义类加载器 执行测试 注意事项 类加载器 概述 类加载器负责读取Java字节代码,并转换成java.lang.Class类的一个实例的代码模块. 类加载器除了用于加载类外,还可用于确定类在Java虚拟机中的唯一性. 任意一个类,都由加载它的类加载器和这个类本身一同确定其在 Java 虚拟

  • 从 JVM 中深入探究 Synchronized作用及原理

    目录 开篇语 Synchronized 使用 synchronized 实现原理 对象头 字节序 Java 中的字节序 如何阅读对象头 偏向锁 获取偏向锁 释放偏向锁 偏向撤销 批量重偏向 批量撤销偏向 Hashcode 去哪了 Lock Record 场景 1 场景2 轻量级锁 获取轻量级锁 加锁过程 释放轻量级锁 重量级锁 获取重量级锁 膨胀过程 竞争锁过程 释放重量级锁 释放锁过程 wait(),notify(),notifyAll() 开篇语 Synchronized,Java 友好的提

  • JVM调优OutOfMemoryError异常分析

    目录 1.Java 堆溢出 1.1 设置JVM参数 1.2 测试代码 1.3 运行OOM日志 2.Java栈.本地方法栈溢出 2.1 设置JVM参数 2.2 测试代码 2.3 运行OOM日志 2.4 Java虚拟机OOM异常 3.Java 运行常量池溢出 3.1 设置JVM参数-注意区分jdk版本 3.2 测试代码 3.3 运行OOM日志 4.Java 方法区溢出-jdk8 4.1 设置JVM参数 4.2 测试代码 4.3 运行OOM日志 5.本机直接内存溢出 5.1 设置JVM参数 5.2 测

  • Native Memory Tracking追踪区域示例分析

    目录 Compiler Internal Symbol Native Memory Tracking Arena Chunk Unknown Compiler Compiler 就是 JIT 编译器线程在编译 code 时本身所使用的内存. 查看 NMT 详情: [0x0000ffff93e3acc0] Thread::allocate(unsigned long, bool, MemoryType)+0x348 [0x0000ffff9377a498] CompileBroker::make_

  • 教你JVM怎么使用native memory

    目录 JRE如何使用native存储 Java堆和GC The Just-in-time (JIT) compiler Classes and classloaders JNI NIO Threads JRE如何使用native存储 今天看到一篇特别好的文章,翻译其中一小段Understanding how the JVM uses native memory Runtime环境提供了被某些未知的用户代码驱动的能力,这使runtime在任何情况下都能使用合适的资源.每一个JVM管理的java应用

  • JProfiler11使用教程之JVM调优问题小结

    安装JProfiler jprofiler_windows-x64_11_0_2 链接: https://pan.baidu.com/s/1EWxW5VT100D1v_HVvKYGqQ?pwd=qif5 提取码: qif5 JProfiler11破解 然后打开破解机器 KeyGen.exe 链接: https://pan.baidu.com/s/13MX6iLFtcmerdGovYjOh4g?pwd=cx7e 提取码: cx7e 配置本地监控 我们启动一个本地项目weblogic,Jboss,t

  • 教你快速搭建 React Native 开发环境

    React Native 官网地址:https://www.reactnative.cn/docs/environment-setup 开发平台 Windows 目标平台 Android 1.安装依赖 必须安装的依赖有 Node.JDK 和 Android Studio,Node 版本不得低于 14,React Native 需要 JDK 11,查看 JDK 版本的指令如下: javac -version 1-1.下载和安装 android studio 1-2.安装 Android SDK 目

  • JVM核心教程之JVM运行与类加载全过程详解

    为什么要使用类加载器? Java语言里,类加载都是在程序运行期间完成的,这种策略虽然会令类加载时稍微增加一些性能开销,但是会给java应用程序提供高度的灵活性.例如: 1.编写一个面向接口的应用程序,可能等到运行时再指定其实现的子类: 2.用户可以自定义一个类加载器,让程序在运行时从网络或其他地方加载一个二进制流作为程序代码的一部分:(这个是Android插件化,动态安装更新apk的基础) 为什么研究类加载全过程? 有助于连接JVM运行过程 更深入了解java动态性(解热部署,动态加载),提高程

  • 解析Java的JNI编程中的对象引用与内存泄漏问题

    JNI,Java Native Interface,是 native code 的编程接口.JNI 使 Java 代码程序可以与 native code 交互--在 Java 程序中调用 native code:在 native code 中嵌入 Java 虚拟机调用 Java 的代码. JNI 编程在软件开发中运用广泛,其优势可以归结为以下几点: 利用 native code 的平台相关性,在平台相关的编程中彰显优势. 对 native code 的代码重用. native code 底层操作

  • 详解JVM中的本机内存跟踪

    1.概述 有没有想过为什么Java应用程序通过众所周知的-Xms和-Xmx调优标志消耗的内存比指定数量多得多?出于各种原因和可能的优化,JVM可以分配额外的本机内存.这些额外的分配最终会使消耗的内存超出-Xmx限制. 在本教程中,我们将列举JVM中的一些常见内存分配源,以及它们的大小调整标志,然后学习如何使用本机内存跟踪监视它们. 2.原生分配 堆通常是Java应用程序中最大的内存使用者,但还有其他人.除了堆之外,JVM还从本机内存中分配出一个相当大的块来维护类的元数据,应用程序代码,JIT生成

  • JVM入门之内存结构(堆、方法区)

    目录 1.堆 1.1 定义 1.2 堆的作用 1.3 特点 1.4 堆内存溢出 1.5 堆内存诊断 2.方法区 2.1 结构(1.6 对比 1.8) 2.2 内存溢出 2.3 常量池 2.4 运行时常量池 2.5 常量池与串池的关系 2.6 StringTable的位置 2.7 StringTable 垃圾回收 2.8 方法区的垃圾回收 3.直接内存 释放原理 1.堆 1.1 定义 是Java内存区域中一块用来存放对象实例的区域[几乎所有的对象实例都在这里分配内存] 通过new关键字创建的对象都

  • Java jvm中Code Cache案例详解

    Code Cache JVM生成的native code存放的内存空间称之为Code Cache:JIT编译.JNI等都会编译代码到native code,其中JIT生成的native code占用了Code Cache的绝大部分空间 相关参数 Codecache Size Options -XX:InitialCodeCacheSize 用于设置初始CodeCache大小 -XX:ReservedCodeCacheSize 用于设置Reserved code cache的最大大小,通常默认是2

  • 面试时必问的JVM运行时数据区详解

    目录 前言 正文 1.运行时数据区(Run-Time Data Areas) 1)程序计数器(Program Counter Register) 2)Java虚拟机栈(Java Virtual Machine Stacks) 3)本地方法栈(Native Method Stacks) 4)堆(Heap) 5)方法区(Method Area) 6)运行时常量池(Run-Time Constant Pool) 2.Java 中有哪几种常量池? 3.class 文件常量池 4.运行时常量池 5.字符串

随机推荐