JVM读书笔记之JVM内存管理

一. Java组件的内存使用
      Java启动后作为一个进程运行在操作系统中,其组件部分需要分配内存。
  • Java堆
          Java堆是 用于存储java对象的内存区域,堆的大小在JVM启动时就一次性向操作系统申请完成,通过-Xmx(最大大小)与-Xms(初始大小)控制大小,一旦分配完成,堆的大小固定,不能在内存不够时向操作系统申请。JVM管理java堆的内存空间,对象创建由java程序创建,管理堆内存的垃圾收集器释放对象所占空间。
  • 线程
           JVM运行实际程序的实体是线程。很多程序根据CPU的核数来分配创建的线程数。
  •  类和类加载器
            Java类和加载类的类加载器也需要内存空间,Sun JDK被存储在永久代(注意:方法区是JVM规范的逻辑概念,不同的虚拟机有不同的实现方式,永久代是Hotspot特有的概念,是方法区的一种实现,java8中永久代被废除,取而代之的是一块与堆不相连的本地内存--元空间)。
          一个类被卸载需要满足三个条件:
  1. Java堆中没有对表示该类加载器的java.lang.ClassLoader对象的引用;
  2. Java堆没有对表示类加载器加载的类的任何java.lang.Class对象的引用;
  3. Java堆该类加载器加载的任何类的所有对象都不再存活。
  • NIO
          NIO是基于通道和缓冲区来执行I/O的新方式,NIO使用java.nio.ByteBuffer.allocateDirec()来分配内存(分配本机内存,而不是java堆内存,与I/O不同)。
  • JNI
          JNI技术使得Java语言与其他语言代码进行交互。Java运行本身也依赖于JNI代码实现类库功能。

二. JVM内存结构(JVM中如何使用内存)
      JVM中按照运行时数据的存储结构来划分内存结构的,JVM在运行java程序时,将他们划分成几种不同格式的数据,分别存储在不同的区域,这些数据称为运行时数据。JVM规范将Java运行时数据划分为6种。
  1. PC寄存器:用于保存当前正常执行程序的内存地址,同时Java是多线程执行的,PC寄存器会记录被中断线程的程序当前执行到的内存地址;
  2. Java栈:每当创建一个线程,JVM就会为其创建一个对应的Java栈,Java栈中有很多栈帧,每个栈帧对应线程的一个方法,每个栈帧包含内部变量区,操作栈和方法返回值等信息。每当一个方法执行完毕时,该栈帧会弹出栈帧元素作为方法返回值,并清除这个栈帧。Java栈的栈顶是当前活动的栈帧(当前正在执行的方法),只有这个活动的栈帧的本地变量能被操作栈使用。Java栈是与线程对应起来的,这个数据不是线程共享的,所以不必关系数据一致性问题。
  3. java堆:存储Java对象的地方,每一个存储在堆中的对象都是对应类的一个副本,它会复制包括父类在内的所有非静态属性。堆是被所有线程共享的,所以要注意同步问题。
  4. 方法区:JVM方法区用于存储Java类结构信息的地方,.class被加载进入JVM后,不同部分会被存储在不同的数据结构(内存区)中,其中常量池,域,方法体,构造函数,实例初始化,接口初始化都存储在这个区域。方法区也属于Java堆的一部分,属于永久代。
  5. 运行时常量池:代表运行时每个.class文件中的常量表,包括:编译期的数字常量,方法或者域的引用。每一个运行时常量池都是方法区中分配的,它是方法区的一部分。
  6. 本地方法栈:本地方法栈是JVM运行Native方法的内存空间。除了代码中包含的常规Native方法会使用这个内存空间,通过JIT技术将一些Java方法重新编译成Native方法,也会用到这个栈。

三. JVM内存分配策略
      1.操作系统中将内存分配策略分为:
  • 静态内存分配:程序编译时就知道每个数据在运行时的存储空间要求,编译时就可以分配固定存储空间;
  • 栈内存分配:动态内存分配,只有在运行时才知道,规定在进入程序模块时,必须知道程序模块所需要的数据区大小;即为在程序入口时知道存储空间。虽然也在运行时分配,但是大小在编译时已经确定。
  • 堆内存分配:当程序运行到相应的代码时才知道存储空间的大小。
       2.Java中内存分配
          根据JVM内存结构,JVM内存分配主要基于堆和栈两种。Java不会在编译时分配内存空间。
  • Java栈的分配
           Java栈的分配与Java线程的创建相关,一个线程的方法调用与返回对应于其Java栈的入栈和出栈(栈帧的压栈与出栈)。栈主要存放一些基本数据类型和对象引用(reference,指向Java堆的句柄池地址),栈的数据可以共享(注意不是线程之间的共享,是栈中的数据可以共享!!!!!!!)。缺点是存在栈中的数据大小与生存期必须固定。
  • Java堆的分配
           每一个Java应用对应一个JVM实例,一个JVM实例对应唯一的Java堆。应用程序在运行中创建的所有实例与数组都放在这个堆中,由应用程序的所有线程共享。Java堆是运行时数据区,对象通过new,newarray等指令建立,不需要显式的释放。优点:运行时动态分配内存的大小,GC进行垃圾回收,收回内存空间;缺点:存取速度比较慢。

四. JVM内存回收策略
      Java数据通常显式的内存申请有两种:1.静】】态内存分配(java栈上的分配);2.动态内存分配(Java堆上的分配)。
      1.静态内存分配与回收
         在Java中静态内存分配是指,Java在编译时就已经确定需要的内存空间,当程序被加载时(进入程序入口)就把内存一次性分配。代码执行完毕后,内存才会被回收(方法执行完毕,栈帧被回收)。
      2.动态内存的分配与回收
         Java堆上对象内存的动态分配,GC算法和收集器判断堆内对象的存活,进行垃圾回收。
         

你可能感兴趣的:(Java,JVM)