您的位置:首页 > 编程语言 > Java开发

Java内存结构和Java内存泄漏

2017-05-16 09:28 162 查看
Java内存结构

方法区:存放要加载的类的信息(名称,修饰符等)、类中的静态变量、类中final类型的常量、类中Field和Method信息。通过Class对象的方法访问的信息来源于方法区。方法区是全局共享的。JVM会回收(GC)方法区中的内存。

堆(Heap):存储对象实例和数组。

本地方法栈: native方法调用的信息。

PC寄存器

JVM方法栈(Stack): 存储基本数据类型 byte short int long float double char boolean;方法的形式参数,方法调用完后从栈空间回收;引用对象的地址,引用完后,栈空间地址立即被回收,堆空间等待GC。

public class Employee {//运行时 jvm把 类信息放入方法区
private int employeeId; //放入栈
private String name; //name引用放入栈 , name对象放入堆
private Date onboardDate;
private String title;
public Employee(int employeeId, String name) {
this.employeeId = employeeId;
this.name = name;
}
public int getEmployeeId() {
return employeeId;
}
public String getName() { // 方法本身放入方法区
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getOnboardDate() {
return onboardDate;
}
public void setOnboardDate(Date onboardDate) {
this.onboardDate = onboardDate;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@Override
public boolean equals(Object obj) {
if(this == obj) return true;
if(!(obj instanceof Employee)) return false;
Employee employee = (Employee)obj;
return this.employeeId == employee.employeeId &&
(this.name == employee.name ||
(this.name != null && this.name.equals(employee.name))
);
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + employeeId;
result = 31 * result + name.hashCode();
return result;
}
public static void main(String[] args) {
Employee employee = new Employee(1, "Tom");//employee引用 放入栈中 Employee对象放入堆中
String name  = employee.getName();
}
}


Java内存泄漏

如果没有强引用指向堆中的对象,JVM可能GC这个对象,释放堆空间。

下面的情况,因为强引用存在,对象不能被回收,可能造成内存泄漏,出现OutOfMemery错误。

示例 1:

Employee employee = new Employee(1, "Tom");
GregorianCalendar calendar = new GregorianCalendar(2017, 5, 1);
Date date = calendar.getTime();
employee.setOnboardDate(date);
date = null; //Date对象不能被GC,因为employee对象中持有Date对象的强引用
employee = null; //Date对象可以被GC


示例 2:散列集合中的对象的状态被改变,从而改变了hash code, 不能用remove方法删除对象。

Employee employee = new Employee(1, "Tom");
Set<Employee> set = new HashSet<>();
set.add(employee);
employee.setName("Jerry");//the hash code of the object is changed
employee = null; //Employee object can not be GC
set.remove(employee); //cannot remove the object due to hash code changed;
//Employee object can not be GC
set = null;//Employee object can be GC now


示例 3:内部类对象持有个对外围类对象的引用。

假设Employee类中定义了一个成员类InnerClass,和一个返回InnerClass对象的方法getInnerClass()。

Employee employee = new Employee(1, "Tom");
Employee.InnerClass inner = employee.getInnerClass();
employee = null;//Employee object can not be GC
inner = null;//Employee object can be GC now


SoftReference

WeakReference

PhantomReference
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  内存泄露 java