JVM、内存相关问题

在 Java 中可以作为GC Roots 的对象主要有以下几种:

1.Java 栈中引用对象。

2.本地方法栈中 JNI 引用的对象。

3.方法区中运行时常量池引用的对象。

4.方法区中静态属性引用的对象。

5.运行中的线程

6.由引导类加载器加载的对象

7.GC控制的对象

 

顺便说一下,内存泄漏和内存溢出的区别(OOM)

系统已经不能再分配出你所需要的空间,比如你需要100M的空间,系统只剩90M了,这就叫内存溢出,比如大图片加载。

内存泄漏:指我们创建开辟了一块内存区域(如创建了一个对象),这个对象已经不使用了,但是其他对象还持有他的引用,导致他不能被回收,这时候就会内存泄漏。

现在 GC 都是可达性算法,当一个对象没有指向 GcRoot 的引用链时,这个对象可以被回收。

 

堆、方法区

方法区和堆一样,是各个线程共享的内存区域,方法区用来存储已被虚拟机加载的类信息、常量、静态变量、及时编译器比以后的戴拿等数据。

堆是用来存放对象实例的。几乎所有的对象实例都在这里分配内存。官方描述:所有的对象实例以及数组都要在堆上分配。

运行时的常量池是方法区的一部分。

class文件中除了有类的 版本、字段、方法、接口等信息外,还有一项信息就是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中的存放。

 

Java虚拟机栈

Java虚拟机栈也是线程私有得,它的生命周期与线程相同。

虚拟机栈描述的是 Java 方法执行的内存模型。

每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。

每一个方法从调用到完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

 

程序计数器

程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。

程序计数器是线程私有的。

如果线程执行的是一个java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址。如果执行的是Native方法,这个计数器值则为空。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMenoryError情况的区域。

 

判断一个类是否“无用”,则需同时满足三个条件:

          (1)、该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例。

          (2)、加载该类的ClassLoader已经被回收。

          (3)、该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

虚拟机可以对满足上述3个条件的无用类进行回收,这里说的是可以回收而不是必然回收。

 

内存优化

使用软引用、弱引用,内存不够的时候会自动回收

不使用的对象置位null,便于回收

上下文(context)的合理使用,非必要尽量使用Application的上下文,弹窗(dialog)必须得使用activity的上下文

合理的创建变量

持有资源对象的引用时,最好采用弱引用

非静态内部类(包括匿名内部类)默认就会持有外部类的引用,当非静态内部类对象的生命周期比外部类对象的生命周期长时,就会导致内存泄露。

非静态内部类导致的内存泄露在Android开发中有一种典型的场景就是使用Handler,很多开发者在使用Handler是这样写的:

资源及时释放(数据库,广播,流等等)

 

Java 的回收机制会自动帮你回收不再被引用的对象,你说的问题里面(A对象里面包含B对象)当A被销毁的时候,B要不要销毁取决于系统里面还有没有引用了B对象的变量,如果有的话则B不会被销毁,否则B也会被回收的

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值