1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.
2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(对象可能在常量池里)(字符串常量对象存放在常量池中。)
压栈,弹栈,现进后出,描述的方法的内存模型,JVM为每个线程创建一个栈,不同线程间不可以共享
3. 堆:存放所有new出来的对象。
分配灵活,速度慢,线程之间共享
4. 静态域:存放静态成员(static定义的)
5. 常量池:存放字符串常量和基本类型常量(public static final)。有时,在嵌入式系统中,常量本身会和其他部分分割离开(由于版权等其他原因),所以在这种情况下,可以选择将其放在ROM中 。
6. 非RAM存储:硬盘等永久存储空间
一个对象的实例化过程:
一、JVM读取指定目录下的.class文件,并且加载进内存。并且先加载此类的父类(在有直接父类的情况下)
二、在堆内存当中开辟内存,分配地址。
三、并在对象的空间内,对空间属性进行默认初始化
四、调用对应的构造函数进行初始化
五、在构造函数当中,第一行会先调用父类的构造函数进行初始化。
六、父类初始化完毕后,再对子类的属性进行显式初始化
七、再对子类的构造函数进行特定初始化
八、初始化完毕后,把地址赋值给引用变量。
class Fu{
static{
System.out.println("父类静态代码块");
}
int n =100;
Fu(){
System.out.println("父类构造方法"+n);
show();
}
Fu(String id,String name){
System.out.println("父类有参构造方法");
}
void show(){
System.out.println("父类方法:"+n);
}
public static void main(String[] args) {
Zi z = new Zi();
//z.show();
}
}
class Zi extends Fu{
int num = 10;
static Date d = new Date();
static{
System.out.println("子类静态代码块");
}
Zi(){
//super();
//super("11", "张三");
System.out.println("子类构造方法");
}
void show(){
System.out.println("子类方法:"+num+":::::"+d.getSeconds());
}
}
父类静态代码块
子类静态代码块
父类构造方法100
子类方法:0:::::21
子类构造方法
在运行期的代码中生成二进制字节码
由于JVM通过字节码的二进制信息加载类的,那么,如果我们在运行期系统中,遵循Java编译系统组织.class文件的格式和结构,生成相应的二进制数据,然后再把这个二进制数据加载转换成对应的类,这样,就完成了在代码中,动态创建一个类的能力了。
nio java 的nio库允许java程序使用直接内存,从而提高性能,速度会高于java堆
方法区是一块永久区
一、堆
堆分为 新生代、老年代
新生代:存放新生成的对象
eden区、s0区(from)、s1区(to)、s0和s1是两块大小相等并且可以互换角色的空间
eden 伊甸园 对象刚实例化后放到eden区,经历过GC后(比如=null)到s0或s1区
默认15次GC后到老年代
垃圾回收算法
1、复制算法
将内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存留对象复制到未被使用的内存块中去,之后清除之前正在使用的内存块中的所有对象,反复去交换两个内存的角色,完成垃圾回收,s0和s1
二、栈
是一块线程私有的内存空间,一个栈一般由三部分组成
1、局部变量表
2、操作数栈
3、帧数据区
三、堆分配参数
-XX:+PrintGC 使用这个参数,虚拟机启动后,只要遇到GC就会打印日志
-XX:+UseSerialGC 配置串行回收器
-XX:+PrintGCDetails 可以查看详细信息,包括各个区的情况
+启用 -禁用
XX 虚拟机级别
-Xms:设置java程序启动时初始堆大小
-Xms:设置java程序能获得的最大堆大小
在实际工作中,我们可以直接将初始的堆大小与最大堆大小设置相等
这样的好处是可以减少程序运行时的垃圾回收次数,从而提高性能
-Xmn 新生代的大小,一般设置为整个堆空间的1/3 ,1/4
-XX:SurvivorRatio 用来设置新生代eden空间和from/to空间的比例
-XX:NewRatio =2 老年代和新生代比例
在实际应用中尽可能将对象预留在新生代中
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/001.dump
把内存溢出的错误信息打印到文件中再用内存分析工具分析内存溢出原因
内存分析工具
Memory Analyzer 1.5.0
-XX:Xss 设置栈空间大小 java.lang.StackOverflowError
-XX:MaxPermSize 方法区(永久区)默认64M 最大
-XX:PermSize 初始化方法区大小
-XX:MaxTenuringThreshold 进入老年代的次数, 默认15次GC进入老年代
大对象(新生代eden区无法装入时,也会直接进入老年代)
对应参数 -XX:PretenureSizeThreshold
四、垃圾回收
算法
1、引用计数法
对象被其他所引用时计数器加1,当引用消失时减1,无法处理循环引用的情况
每次进行加减操作比较浪费系统性能
2、标记清除法
3、复制算法
4、标记压缩法 老年代中使用的就是标记压缩法
5、分代算法
6、分区算法
五、TLAB
线程本地分配缓存,一个线程专用的内存分配区域,是为了加速对象分配而生的,每一个线程
都会产生一个TLAB,该线程独享的工作区域,java虚拟机使用这种TLAB区来避免多线程冲突问题
TLAB空间一般不会太大,当大对象无法在TLAB分配时,则会直接分配到堆上
-XX:+UseTLAB 使用TLAB
-XX:+TLABSize 设置TLAB大小
-XX:+TLABRefillWasteFraction
设置维护进入TLAB空间的单个对象大小,他是一个比例值,默认为64,即如果对象大于整个空间的1/64则在堆创建对象
-XX:+PrintTLAB 查看TLAB信息
-XX:+ResizeTLAB 自调整TLABRefillWasteFraction阀值