JVM的内存管理、对象的生命周期、内存泄漏
1 JVM内存
分为“堆”、“栈”和“方法区”三个区域,分别用于存储不同的数据
1.1 堆
JVM在其内存空间开辟一个称为”堆”的存储空间,这部分空间用于存储使用new关键字所创建的对象。
1.2 栈
JVM在其内存空间开辟一个称为”栈”的存储空间,这部分空间用于存储程序运行时在方法中声明的所有局部变量。
1.3 方法区
方法区用于存放类的信息,Java程序运行时,首先会通过类装载器载入类文件的字节码信息,经过解析后将其装入方法区,类的各种信息(包括方法)都在方法区存储。
2 对象的生命周期
2.1 使用new运算符创建对象
2.1.1 Java虚拟机先检查类是否加载, 如果没有加载就加载类信息到方法区
2.1.2 根据类信息中的属性定义在堆内存中开辟存储空间, 并且每个属性有默认值
2.1.3 调用构造器, 执行构造器中属性初始化过程, 构造器结束时候, 释放构造器中全部的局部变量
2.1.4 new运算返回对象的引用(即:对象在堆中的地址)
2.2 利用引用操作使用对象 - 使用引用操作对象: 访问对象的属性和方法. - 可以反复更改对象的属性状态.
2.3 对象在不被引用时候被垃圾回收器回收 - 当一个对象不再被引用时候, 对象就称为内存垃圾. 内存垃圾在适当时候被垃圾回收器回收.
2.4 注意
2.4.1 对象生存期中构造器只能执行一次. 在对象生存期间, 可以反复调用其方法, 反复访问其属性.
2.4.2 对象的属性随着对象在堆中分配.
2.5 图片示意图
2.6 代码实现
1 public class Demo { 2 public static void main(String[] args) { 3 //对象的生命周期 4 Circle c1 = new Circle(3, 4, 5); 5 System.out.println(c1); 6 Circle c2 = new Circle(3, 4, 6); 7 System.out.println(c2); 8 //将引用赋值为null, 对象不再被引用 9 //对象变成内存垃圾, 将被垃圾回收器回收. 10 c1=null; 11 c2=null; 12 } 13 } 14 class Circle{ 15 int x,y,r; 16 17 public Circle(int x, int y, int r) { 18 this.x = x; 19 this.y = y; 20 this.r = r; 21 } 22 23 public String toString() { 24 return x+","+y+","+r; 25 } 26 }
3 内存泄漏
尽管Java的垃圾回收器可以回收堆内存, 但是当Java程序员操作对象不当时候, Java也会发生内存泄漏.
3.1 什么情况下会发生内存泄漏
应用程序大量创建对象, 并且保持这些对象的引用, 进而造成垃圾回收器不能有效释放对象占用的堆内存空间, 最终内存耗尽出现内存泄漏.
3.2 避免内存泄漏的方法
对象使用以后,及时将引用对象的引用变量赋值为null, 使对象变成垃圾对象, 及时被回收并且释放堆内存, 就可以避免内存泄漏.
3.3 代码实现
1 package cn.fury.day11; 2 3 public class MemoryLeakDemo01 { 4 public static void main(String[] args) { 5 Foo[] ary = new Foo[40000000]; 6 for(int i=0; i<ary.length; i++){ 7 Foo f = new Foo(); 8 // f = null; 9 ary[i] = f; // 创建了许多对象,并且将对象的引用(即:地址)放到了一个数组里面 10 } 11 } 12 } 13 class Foo{ 14 int a; 15 int b; 16 int c; 17 } 18 /* 19 尽管Java的垃圾回收器可以回收堆内存, 但是当Java程序员操作对象不当时候, Java也会发生内存泄漏. 20 》何时发生内存泄漏: 应用程序大量创建对象, 并且保持这些对象的引用, 21 进而造成垃圾回收器不能有效释放对象占用的堆内存空间, 最终内存耗尽出现内存泄漏. 22 》避免内存泄漏的办法: 对象使用以后,及时将引用对象的引用变量赋值为null, 23 使对象变成垃圾对象, 及时被回收并且释放堆内存, 就可以避免内存泄漏. 24 */