Java:内存机制

Java内存主要分为四种:堆区、栈区、全局数据区、全局代码区

堆区:保存所有的对象名称,更准确的说法是保留了对象引用的地址
栈区:保存每个对象的具体属性内容
全局数据区:保存static类型的属性
全局代码区:保存所有的方法定义

堆取与栈区:
用来存放new出来的对象和数组。new出来后,会在堆区分配内存,而栈区存放的内容即是相对应的堆区的地址。而堆区才是真正存放数据的地方。

为了更形象的说明问题,我们新建一个User类,里面存放了username和password

public class User {
	private String username;
	private String password;
}

如果运行了User a = new User();则内存的分配情况如下:
这里写图片描述

由于只是new了a实例,并未对username和password进行赋值,所以它们的内容为null

在调用了User a = new User()的基础上,再执行User b = new User();则内存的分布情况如下:
这里写图片描述

再执行了User b = new User();后继续执行User b = a;则内存分配如下:
这里写图片描述

如果不是执行User b = new User();而是执行User b = a;则内存分配情况如下:
这里写图片描述

全局数据区:保存所有static属性的数据。
全局代码区:保存所有方法的定义。

补充:静态代码块

public class MainClass {

	public static void main(String[] args) {
		new A();
	}
}

class A {
	static {
		System.out.println("Hello");
	}
	
	static {
		System.out.println("A");
	}
}

输出结果:

Hello
A

静态代码块只会加载一次,且要用到该类时才会加载。静态数据也只会加载一次

GC回收机制
GC回收机制一般分为两个阶段:finalization【终结】: 指运行这个对象的finalize的方法和reclamation【回收】: 回收被这个对象使用的内存。

步骤:
1、先确定该对象或者数组不可达【即为被栈区引用】。
2、如果该对象有finalize方法,则将该对象加入到finalization queue中,等待回收机制将其回收。
3、回收该对象占用的内存。

GC实际上回收的还是对象占用的内存空间。

采用Reference Counting的垃圾回收器
对于采用Reference Counting的垃圾回收器,系统为堆上每一个对象都维护一个计数器,当一个对象被创建并且别引用时,这个计数就被置为1。当有新的变量引用该对象,计数器进行自加运算。当一个引用超出作用范围或者被赋予新值的时候,计数器进行自减运算。引用计数为0的对象,会被作为垃圾回收。当一个对象被回收,该对象所引用的对象的引用计数都会相应减少,因而,一个对象的回收有时会引起其它对象的回收。
Reference Counting方式的垃圾回收器,好处在于可以在很短的时间内运行,不会长时间的中断普通的程序运行,因而在RealTime的系统中应用较为普遍。
Reference Counting方式的垃圾回收器,问题在于无法识别循环引用,比如父类对象还有子类引用的情况,即便父类和子类都已经不再能被访问到(unreachable),引用计数也把它们清除。另外一个问题是引用计数器的加减运算会增加系统的计算开销。

猜你喜欢

转载自blog.csdn.net/new_Aiden/article/details/50973705