java convert thumbnail 内存不释放 java 内存文件_jvm


先上一张流程图,留一个大致印象。这里不是深究JVM运行原理的更底层的实现,而旨在梳理一个逻辑。

首先看看经过编译得到的class文件

Class文件

  • class文件包含JAVA程序执行的字节码,文件开头有一个0xcafebabe(16进制)的特殊标志,数据严格按照格式紧凑排列在class文件中的二进制流,中间没有任何分割符。
  • class文件包含很多信息,包括版本、访问标志、常量池、当前类、父类、接口、字段、方法、属性。

了解了class文件的基本内容后,再来看看最重要的JVM运行时数据区

JVM运行时数据区

  • 线程共享部分:方法区、堆内存
  • 线程独占部分:虚拟机栈、本地方法栈、程序计数器

方法区:

JVM用来存储加载的类信息(构造方法/接口定义)、常量、静态变量、运行时常量池等数据。在虚拟机规范中这是一个逻辑区,可以理解成一种规范,根据不同的虚拟机有不同的具体实现,永久代是Hotspot针对这一规范的一种实现,这种实现也在不断的演进:
在Java 6中,方法区中包含的数据,除了JIT编译生成的代码存放在native memory的CodeCache区域,其他都存放在永久代;
在Java 7中,Symbol的存储从PermGen移动到了native memory,并且把静态变量从instanceKlass末尾(位于PermGen内)移动到了java.lang.Class对象的末尾(位于普通Java heap内);
在Java 8中,永久代被彻底移除,取而代之的是另一块与堆不相连的本地内存——元空间(Metaspace),‑XX:MaxPermSize 参数失去了意义,取而代之的是-XX:MaxMetaspaceSize。

堆内存:

堆内存的划分如下图,可细分为老年代、新生代。JVM启动时创建,用于存放对象的实例。垃圾回收器主要就是管理堆内存。

java convert thumbnail 内存不释放 java 内存文件_jvm_02


常用的参数设置如下:

参数

描述

-Xms

堆内存初始大小,单位m、g

-Xmx

(MaxHeapSize) 堆内存最大允许大小,一般不要大于物理内存的80%

-XX:PermSize

非堆内存初始大小,一般应用设置初始化200m,最大1024m就够了

-XX:MaxPermSize

非堆内存最大允许大小

-XX:NewSize(-Xns)

年轻代内存初始大小

-XX:MaxNewSize(-Xmn)

年轻代内存最大允许大小,也可以缩写

-XX:SurvivorRatio=8

年轻代中Eden区与Survivor区的容量比例值,默认为8,即8:1

-Xss

堆栈内存大小

虚拟机栈:

每个线程都在这个空间有一个私有的空间。线程栈由多个栈帧(Stack Frame) 组成。栈帧是用于虚拟机执行时方法调用和方法执行时的数据结构,一个线程会执行一个或多个方法,一个方法对应一个栈帧。栈帧内容包括:局部变量表(一组变量值的存储空间,基本单位为变量槽spot,用于存放方法参数和局部变量)、操作数栈(也称操作栈,可看作方法执行算术运算或者是调用其他的方法进行参数传递时的媒介)、动态链接、方法返回地址、附加信息等。栈内存默认最大是1M,超出则抛StackOverflowError。

本地方法栈:

虚拟机执行Native本地方法的栈,和虚拟机栈的主要区别是执行的方法不同。在虚拟机规范没有规定具体的实现,由不同的虚拟机厂商去实现。HotSpot虚拟机中虚拟机栈和本地方法栈的实现方式是一样的,超出大小后也会抛出StackOverflowError。

程序计数器:

程序计数器(Program Counter Register)是一块较小的内存空间,记录当前线程执行字节码的位置,存储的是字节码指令地址。CPU同一时间只会执行一条线程中的指令,JVM多线程会轮流切换并分配CPU执行时间,在线程切换后,需要通过程序计数器来回复正确的执行位置。
特点:

  • 线程私有
  • JVM规范中唯一没有规定OutOfMemoryError情况的区域
  • 如果执行Native方法,则计数器值为空

总结

最后总结下程序运行的过程:
1.编译,经过编译后加载信息到方法区;
2.JVM创建线程来执行代码,此时会在虚拟机栈、程序计数器分配一定的空间;