Java内存结构和Java内存泄漏

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值