Android技术知识Android开发经验谈Android进阶之路

JVM内存分配回收入门(一)

2020-01-13  本文已影响0人  唠嗑008

前沿

菜鸟Android程序员入门jvm虚拟机,如有错误,欢迎批评指正。我们都知道Java的内存管理是交由jvm来管理的,这很方便,但是也带来了一些困扰,一旦出现内存泄漏和内存溢出方面的问题,如果不了解jvm虚拟机是如何分配回收内存的,那排除bug将会是非常困难的工作。

为什么要学习jvm内存管理?
我觉得起码学个入门级的吧,知道平时代码中那些对象,变量,方法在内存中是如何创建和回收的。我负责任的告诉你,真的不是为了装逼,而是为了解决实际问题。
我的理由如下:
1、解决常见的内存泄漏和oom;
2、内存优化;
3、在开发中写出更健壮的程序,减少一些内存bug或者说增加内存负担的问题;
4、现阶段的面试大概率会问。

关于运行时数据区

在JVM加载class文件的时候,JVM会用一段空间来存储程序执行期间需要用到的数据和相关信息,这段空间一般被称作为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存。我们常说的内存管理(内存分配和回收)就是针对这段空间进行管理。

JVM运行时数据区

根据 JVM 规范,JVM 内存共分为方法区虚拟机栈本地方法栈程序计数器五个部分。其中方法区是被所有线程共享的一块内存区域,在虚拟机启动时创建,生命周期与虚拟机相同;而后面3个则是线程私有,生命周期与线程相同。

注意:这是 JVM 规范,不同虚拟机,不同版本在实现上虽然有所不同,但总体上是按照这个规范来做的

下面简单介绍一下这5个数据区域。

这里重点看一下方法区堆(Heap)虚拟机栈(VM Stack);而在平时的应用开发中做的内存优化又主要是堆(Heap),这下工作就变得没那么复杂了。

下面通过一个例子来讲解内存分配:

public class Person {
    public String name;
    public int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class Test {
    public static void main(String[] args) {

        int num = 1; //1
        Person person = new Person("张三", 20); //2

        change1(num); //3
        change2(person); //4
    }

    private static void change1(int n) {
        n = 11;
    }

    private static void change2(Person p) {
        p = new Person("李四", 21); //5
    }
}

内容很简单,在java的main()方法中定义了一个变量num,创建了一个对象Person,然后再调用change1(int n)change2(Person p)方法

运行过程

1

首先这段java程序是从main()方法作为入口的,
1、当运行到1时,会把局部变量num加载到栈内存;
2、当运行到2时,jvm会先把Person .class加载到方法区,方法区里面存放的就是class的数据结构;然后在堆内存中开辟一个空间来存储Person的实例,且在堆内存的地址为0x001;接着把引用person放在栈中,这个引用指向的就是0x001
3、当调用change1(int n)时,因为n是局部变量,所以会把n放到栈中,并且给n赋值,当方法执行完毕的时候,会立即释放n所占用的栈空间;
4、 当调用change2(Person p)时,因为p是局部变量,所以会把p放到栈中,由于是引用类型的变量,pperson指向堆中的同一个对象;
5、当执行到5时,会在堆内存中重新创建一个新的Person对象,然后p的指针地址不再指向之前的0x001,而是指向新的对象的地址0x002change2(Person p)方法执行完后会立即释放p的栈内存,但是在堆内存中的对象不会立即回收,而是等待gc自动回收。

总结

1、栈中存放的是局部变量(包括引用),如果是普通变量的话存放的是值;如果是引用的话,存放的是堆内存的指针;在使用时入栈,用完就立即出栈;
2、堆内存存放的就是创建的对象/实例,堆是内存中比较大的一块区域,是垃圾回收器管理的主要区域,因此很多时候也被称做“GC 堆”;
3、栈和堆的内存释放不是同步的。方法结束,栈中的局部变量立即销毁,但是堆中对象不一定马上销毁,而是等垃圾回收扫描时才可以被销毁,具体的算法后面章节再讲;
4、创建一个对象时,类的成员变量会存储在堆内存,但是成员方法不会,你想想如果一个类创建了多个对象 ,每个方法都入栈,那多占内存啊?类的方法是该类的所有对象共享的,只有一套,在调用方法时,会通过堆内存中的实例找到方法区中相对应的方法。

参考
【Java千问】你了解Java内存结构么(Java7、8、9内存结构的区别)
jvm学习一:类加载过程详解

上一篇下一篇

猜你喜欢

热点阅读