今天看JVM的过程中收获颇丰,但一想到这些学习心得将来可能被遗忘,便一阵恐慌,自觉得以后要开始坚持做读书笔记了。
操作系统层面的内存管理
物理内存是一切内存管理的基础,Java中使用的内存和应用程序的内存一样是从物理内存申请下来的内存。物理内存也就是寄存器,通过地址总线与CPU相连,通常情况下地址总线与寄存器有着相同的位数,同时也决定了处理器最大可寻址的地址空间。
为了提高物理内存的利用率而产生了虚拟内存,也就是逻辑上的内存。为了保证操作系统和应用程序的稳定性,运行在操作系统中的用户程序不能访问操作系统所使用的内存空间,内存空间因而被划分为了内核空间和用户空间。
内存的交互中总结为下图
Java中需要使用内存的组件
- Java堆
一旦分配完成,堆的大小就将固定,不能在内存不够时再向操作系统中重新申请,同事当内存空闲时也不能将多余的空间交还给操作系统。 - 线程
通常JVM为线程创建的堆栈在256KB~756KB之间。 - 类和类加载器
任何系统类或通过应用程序加载器加载的任何应用程序类都不能在运行时释放(存储在堆中,永久代)。换句话说,加载其实是一种I/O操作,生成的类字节码对象在堆中的方法区中,提供执行指令,提供运行时常量池,并且可以作为对象被操作。 - NIO
分配的是内核空间而不是用户空间上Java堆中的内存,可以避免从内核空间到Java堆上的切换操作,但是通常需要显示的调用System.gc()来释放NIO持有的内存。 - JNI
本机代码如C语言程序可以调用Java方法,也会增加Java运行时内核空间中的本机内存内存占用。
JVM内存结构
在Java虚拟机规范中将Java运行时数据划分为6种
- PC寄存器数据
- Java栈
- 堆
- 方法区
方法区这个存储区域也属于Java堆中的一部分(永久区) - 本地方法区
本地方法栈是为了JVM运行Native方法准备的空间,由于很多Native方法都是用C语言实现的,所以它通常又叫C栈。 - 运行时常量池
在用户空间Java堆上的方法区中。
操作系统的内存分配策略
- 静态内存分配策略
编译时计算存储空间需求,加载时一次性分配内存空间
如:堆的创建 - 栈式内存分配策略
运行中进入一个模块时,在知道该模块所需的数据区大小时才能为其分配内存
如:数组、malloc - 堆式内存分配策略
当程序真正运行到相应代码时才会知道空间大小,并为其分配内存
如:集合、创建对象
Java中的内存分配详解
- Java内存分配给栈
创建线程:堆式内存分配策略,创建线程栈
激活方法:栈式内存分配策略,JVM根据操作栈大小创建栈帧,并在线程栈中压入该栈帧 - Java堆中分配内存
创建对象:堆式内存分配策略,JVM在堆上为该对象分配内存空间
所有对象的存储空间都是在堆中分配的,但该对象的引用却是在栈帧中压入的
JVM内存回收策略
- 静态内存分配和回收
栈上的内存分配和回收(弹出栈帧) - 动态内存分配和回收
堆中的内存分配和回收(垃圾回收)
这里分了动态和静态,其实我更喜欢用操作系统的栈式内存分配策略和堆式内存分配策略来解释
- 垃圾回收
JVM的垃圾回收关键在于整体的效率优化上,这里讲解了垃圾回收算法的发展和常见的内存问题,现在还看不懂