Android中的原始类型是否进行垃圾回收?

16

我知道这可能是一个愚蠢的问题,但我的背景更多是c++和管理自己的内存。

目前,我正在尽可能地减少我的一个游戏中的每一个分配,以尝试降低垃圾回收和感知的“延迟”频率,因此,对于我创建的每个对象变量(例如String和Rect),我正在确保在构造函数中预先创建它,而不是在简单的10行函数中创建临时变量......(我希望这有意义)

无论如何,今晚我又做了一些工作,我意识到我的关于垃圾回收和原始类型(int、boolean、float)的假设可能是完全错误的。这些原始类型变量(比如int、float、boolean等)是否会在我每秒钟调用20次的10行函数中创建,从而加重了垃圾回收问题呢?

所以,一年前我每隔几秒钟就会在logcat中看到一条消息,像这样:

GC freed 4010 objects / 484064 bytes in 101ms

现在我大约每15-90秒左右才会看到这个消息......

那么重新表达我的问题:当看到这条消息时,原始类型(int、float、boolean等)是否被包括在内?

3个回答

25

原始类型不是对象,因此它们不会引起任何垃圾回收。但是,你必须非常小心,因为由于装箱,一个原始类型可以很容易地变成一个对象,而无需你明确地这样做。

例如,如果你想要一个整数键的HashMap<>,你应该使用HashMap。请注意,因为"int"不是一个对象,它不能用于容器中。Integer是原始int的对象版本。当你编写像这样的代码时,一个Integer对象将自动为你创建:

HashMap<Integer, Object> map = new HashMap<Integer, Object>();
int someNum = 12345;    // no object created.
map.put(someNum, null); // Integer object created.

请注意,如果您不使用泛型,将发生完全相同的情况,但更为隐藏:

HashMap map = new HashMap();
int someNum = 12345;    // no object created.
map.put(someNum, null); // Integer object created.

对于这种情况,您可以使用Android的SparseArray类,它是一个原始整数键的容器。


6
似乎答案是否定的。在Java中,原始类型被放置在堆栈上而不是堆中,只有对象才会被垃圾回收。我在许多地方找到了关于这个问题的简短参考,请查看维基百科。如果你想看一些更详细的内容,可以看一篇有关JVM垃圾回收实现的论文,其中更明确地解释了原始类型存储在物理上分离的内存位置中,因此不会被错误地包含在垃圾回收中(请点击这里)。如果你想快速浏览,第4页是最直接解释这个问题的地方。
以下是Android特定的线程,说明gc仅扫描指针以及如何检查它

安卓系统不运行标准的基于堆栈的JVM,而是拥有自己的基于寄存器的虚拟机。 - mikerobi

2

[注意:由于我还没有完全的评论权限,所以我将其作为单独的答案添加。]

看起来在Java中原始类型被放在堆栈上而不是堆上,只有对象才会被垃圾回收。

这并不完全准确。原始类型可以保存在局部变量中,也可以作为类的静态或实例字段。在后一种情况下,它们确实存储在堆上,但它们重要的是没有自己的“生命周期”,特别是它们不会与包含它们的对象分开进行垃圾回收。

Android没有运行标准的基于堆栈的JVM,它有自己的基于寄存器的虚拟机。

这是一个正确的说法,但它也有点误导,离题了。实际上,在一个方法调用另一个方法(等等)时,这些方法的激活帧存储在Dalvik实现的堆栈上。不同之处在于,当单独查看激活帧时,Dalvik激活帧不包含一个可变大小的堆栈。在这个方面,Dalvik排列激活帧的方式更像传统的类C语言(如C或C ++)的处理方式。


等到他们因为方法调用中的自动变量没有默认平凡构造函数而出现N.P.E.,然后尝试使用类型擦除作为唯一线索来追踪它 - ope的基本问题与隐藏对象创建和G.C.有关,这对于“C”风格的编程范式来说有点难以管理,在这种范式中,人们可以使用~this完成“D”所做的事情...虽然唯一有效的方法是使用synchronized关键字并重复使用对象引用(这将引起许多已经成为Java传统主义者的哀嚎),所以O.P.真正需要做的是阅读Hans-J. Boehm在gc.h中的评论。 - Nicholas Jordan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接