java内存简单介绍

入门

首先我们要先明白java内存的组成,Java虚拟机中分为堆和非堆,众所周知,堆是存放新建的对象的地方。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给 自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法 的代码都在非堆内存中。


jvm内容区域模型     

  1. 方法区 -XX:PermSize 和-XX:MaxPermSize
    -XX:PermSize 和 -XX:MaxPermSize 参数限制方法区的大小。
  2. 虚拟机栈
    存储局部变量表(包括参数)、操作栈、方法出口等信息。
    局部变量表存放了编译器可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(引用指针,并非对象本身)
  3. 本地方法栈
    与虚拟机栈基本类似,区别在于虚拟机栈为虚拟机执行的java方法服务,而本地方法栈则是为Native方法服务。(native相当于abstract修饰符)

  4. 也叫做java 堆、GC堆是java虚拟机所管理的内存中最大的一块内存区域,也是被各个线程共享的内存区域,在JVM启动时创建。该内存区域存放了对象实例及数组(所有new的对象)。其大小通过-Xms(最小值)和-Xmx(最大值)参数设置,-Xms为JVM启动时申请的最小内存,默认为操作系统物理内存的1/64但小于1G,-Xmx为JVM可申请的最大内存,默认为物理内存的1/4但小于1G,默认当空余堆内存小于40%时,JVM会增大Heap到-Xmx指定的大小,可通过-XX:MinHeapFreeRation=来指定这个比列;当空余堆内存大于70%时,JVM会减小heap的大小到-Xms指定的大小,可通过XX:MaxHeapFreeRation=来指定这个比列,对于运行系统,为避免在运行时频繁调整Heap的大小,通常-Xms与-Xmx的值设成一样。
  5. 程序计数器
    最小的内存区域,它的作用是当前线程所执行的字节码的行号指示器,在虚拟机的模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、异常处理、线程恢复等基础功能都需要依赖计数器完成。

Java堆内存的要点

  1. Java堆内存是操作系统分配给JVM的内存的一部分。
  2. 当我们创建对象时,它们存储在Java堆内存中。
  3. 为了便于垃圾回收,Java堆空间分成三个区域,分别叫作New Generation, Old Generation或叫作Tenured Generation,还有Perm Space。
  4. 你可以通过用JVM的命令行选项 -Xms, -Xmx, -Xmn来调整Java堆空间的大小。不要忘了在大小后面加上”M”或者”G”来表示单位。举个例子,你可以用 -Xmx256m来设置堆内存最大的大小为256MB。
  5. 你可以用JConsole或者 Runtime.maxMemory(), Runtime.totalMemory(), Runtime.freeMemory()来查看Java中堆内存的大小。
  6. 你可以使用命令“jmap”来获得heap dump,用“jhat”来分析heap dump。
  7. Java堆空间不同于栈空间,栈空间是用来储存调用栈和局部变量的。
  8. Java垃圾回收器是用来将死掉的对象(不再使用的对象)所占用的内存回收回来,再释放到Java堆空间中。
  9. 当你遇到java.lang.outOfMemoryError时,不要紧张,有时候仅仅增加堆空间就可以了,但如果经常出现的话,就要看看Java程序中是不是存在内存泄露了。
  10. 请使用Profiler和Heap dump分析工具来查看Java堆空间,可以查看给每个对象分配了多少内存。

方法区的特性

同 Java 堆一样,方法区也是全局共享的一块内存区域 方法区的作用是存储 Java 类的结构信息,当我们创建对象实例后,对象的类型信息存储在 方法堆之中,实例数据存放在堆中;实例数据指的是在 Java 中创建的各种实例对象以及它 们的值,类型信息指的是定义在 Java 代码中的常量、静态变量、以及在类中声明的各种方 法、方法字段等等;同事可能包括即时编译器编译后产生的代码数据。
JVMS 不要求该区域实现自动的内存管理,但是商用 JVM 一般都已实现该区域的自动内存 管理。 方法区分配内存可以不连续,可以动态扩展。 该区域并非像 JMM 规范描述的那样数据一旦放进去就属于 “永久代”;在该区域进行内存回 收的主要目的是对常量池的回收和对内存数据的卸载;一般来说这个区域的内存回收效率比 起 Java 堆要低得多。 当方法区无法满足内存需求时,将抛出 OutOfMemoryError 异常


运行时常量池的特征

运行时常量池是方法区的一部分,所以也是全局共享的。 其作用是存储 Java 类文件常量池中的符号信息。 class 文件中存在常量池(非运行时常量池),其在编译阶段就已经确定;JVM 规范对 class 文件结构有着严格的规范,必须符合此规范的 class 文件才会被 JVM 认可和装载。 运行时常量池 中保存着一些 class 文件中描述的符号引用,同时还会将这些符号引用所翻译 出来的直接引用存储在 运行时常量池 中。
运行时常量池相对于 class 常量池一大特征就是其具有动态性,Java 规范并不要求常量只 能在运行时才产生,也就是说运行时常量池中的内容并不全部来自 class 常量池,class 常 量池并非运行时常量池的唯一数据输入口;在运行时可以通过代码生成常量并将其放入运行 时常量池中。 同方法区一样,当运行时常量池无法申请到新的内存时,将抛出 OutOfMemoryError 异常。


HotSpot 方法区变迁

  1. JDK1.2 ~ JDK6
    在 JDK1.2 ~ JDK6 的实现中,HotSpot 使用永久代实现方法区;HotSpot 使用 GC 分代实现方法 区带来了很大便利;
  2. JDK7
    由于 GC 分代技术的影响,使之许多优秀的内存调试工具无法在 Oracle HotSpot之上运行,必须 单独处理;并且 Oracle 同时收购了 BEA 和 Sun 公司,同时拥有 JRockit 和 HotSpot,在将 JRockit 许多优秀特性移植到 HotSpot 时由于 GC 分代技术遇到了种种困难,所以从 JDK7 开始 Oracle HotSpot 开始移除永久代。
    JDK7中符号表被移动到 Native Heap中,字符串常量和类引用被移动到 Java Heap中。
  3. JDK8
    在 JDK8 中,永久代已完全被元空间(Meatspace)所取代。

coding个人博客链接

参考资料

猜你喜欢

转载自www.cnblogs.com/cosy1213/p/9350546.html