Linux的进程内存模型是由用户空间和内核空间组成。html
在应用程序中,若是直接操做外围设备,访问时也不知道其余程序有没有在访问,也不知道哪一段能够用的,你们你争我抢的,都乱套了,并且也不安全。因此须要一位管理者--操做系统。操做系统将真实的物理地址隔离起来,给每一个程序分配一段虚拟地址,经过mmap将真实地址和虚拟地址起来,好比虚拟地址是0x00,那么它真实的物理地址多是0x1c。在真实物理地址它可能不是一段连续的地址,可是在虚拟地址是连续的就能够了。前端
虚拟空间还能够进行细分:java
内核空间(进程管理,存储管理,文件管理,设备管理,网络系统等)
----------
栈
FileMapping
堆
BSS
Data
text
复制代码
进程由n个线程组成,在JVM中,又对进程以线程为单位对内存进行划分。android
在操做系统看来,JVM是一个程序,而Java程序只是运行在程序上的程序,因此JVM须要模拟程序运行的环境。程序员
(图片来源:csdn-骁兵)
web
public class Test {
public void test(int b, int a) {
int x = 6;
if (b > 0) {
String str = "VeCharm";
}
int y = a;
int c = y + b;
}
}
----------------
javac Test.java
javap -v Test
----------------
class信息:
Last modified 2019-3-31; size 347 bytes
MD5 checksum b0e2fc2ec7a2d576136a693c77213446
Compiled from "Test.java"
public class com.vecharm.lychee.sample.api.Test
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
...
{
public com.vecharm.lychee.sample.api.Test();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
public void test(int, int);
descriptor: (II)V
flags: ACC_PUBLIC
Code:
stack=2, locals=6, args_size=3
0: bipush 6
2: istore_3
3: iload_1
4: ifle 11
7: ldc #2 // String VeCharm
9: astore 4
11: iload_2
12: istore 4
14: iload 4
16: iload_1
17: iadd
18: istore 5
20: return
LineNumberTable:
line 7: 0
line 8: 3
line 9: 7
line 11: 11
line 12: 14
line 13: 20
StackMapTable: number_of_entries = 1
frame_type = 252 /* append */
offset_delta = 11
locals = [ int ]
}
SourceFile: "Test.java"
复制代码
public class Test {
public void test(int b, int a) {
int x = 6;
if (b > 0) {
String str = "VeCharm";
}
int y = a;
int c = y + b;
}
}
----------------
javac Test.java
javap -v Test
----------------
class信息:
...
Constant pool:
#1 = Methodref #4.#14 // java/lang/Object."<init>":()V
#2 = String #15 // VeCharm
#3 = Class #16 // com/vecharm/lychee/sample/api/Test
#4 = Class #17 // java/lang/Object
#5 = Utf8 <init>
#6 = Utf8 ()V
#7 = Utf8 Code
#8 = Utf8 LineNumberTable
#9 = Utf8 test
#10 = Utf8 (II)V
#11 = Utf8 StackMapTable
#12 = Utf8 SourceFile
#13 = Utf8 Test.java
#14 = NameAndType #5:#6 // "<init>":()V
#15 = Utf8 VeCharm
#16 = Utf8 com/vecharm/lychee/sample/api/Test
#17 = Utf8 java/lang/Object
...
SourceFile: "Test.java" 复制代码
CONSTANT_Utf8 | UTF-8编码的Unicode字符串 | |
CONSTANT_Integer | int类型字面值 | |
CONSTANT_Float | float类型字面值 | |
CONSTANT_Long | long类型字面值 | |
CONSTANT_Double | double类型字面值 | |
CONSTANT_Class | 对一个类或接口的符号引用 | |
CONSTANT_String | String类型字面值 | |
CONSTANT_Fieldref | 对一个字段的符号引用 | |
CONSTANT_Methodref | 对一个类中声明的方法的符号引用 | |
CONSTANT_InterfaceMethodref | 对一个接口中声明的方法的符号引用 | |
CONSTANT_NameAndType | 对一个字段或方法的部分符号引用 |
看到这想必就已经知道了一个从一个Java文件到内存是如何运做的了。类从加载到虚拟机内存中开始到卸载内存为止,它的整个生命周期包括:加载,验证,准备,解析,初始化,使用,和卸载7个阶段,其中验证,准备,解析3个部分被称为链接。数据库
加载,验证,准备,初始化和卸载这5个阶段是肯定的,类的加载过程是必须按照顺序来,而解析阶段这个能够在初始化以后开始,这是为了支持运行时绑定(动态绑定)。编程
说到底,编程就是编的只是数据和指令,来总结一下流程。api
在内存模型中,咱们须要重点关注的就是Heap。由于它是由咱们来控制的,处理不当容易发生OOM。内存处理的步骤无非也就三个: 申请,整理,清除。管理内存打个比方就和管理卖戏票的,观众台也就几十个座位,都是宝贵的资源。vip大户,里边走,直接坐贵席。其余的买计时票看,每隔必定时间把到时的人清出去,但常常有人到时赖着不走,隔一段时间催他才走。有时候座满了,只能把到时的赖皮清出去,不想走能够交钱。有时候人家成群结队的买票,天然要调配一下,清理出一些连座的给客户对吧。若是是一大帮人来看,更是欢迎,vip里面请。缓存
在Java的堆模型中划分为三个区。
管理对象的生命周期
生存仍是毁灭,是经过这个对象到GC Root的可到达性来决定的。能做为GC Root的对象有四种。
引用类型有四种,强引用,软引用,弱引用,虚引用。
结语,限于篇幅,只是初略的整理了一下大体的流程,参考《深刻Java虚拟机》等。