4

在这里,我发现了一个问题,即同一类的实例大小在不同版本的 JVM 中不一样(在1.6.0_21中为40 ,在1.6.0_31中为24)。即使,代码是相同的。你以前有没有人遇到过类似的问题?或者你有什么建议吗?

JDK 1.6.0_21

# java -version 
java version "1.6.0_21"
Java(TM) SE Runtime Environment (build 1.6.0_21-b06)
Java HotSpot(TM) 64-Bit Server VM (build 17.0-b16, mixed mode)

# java obj.ObjectSize &

# jps | grep ObjectSize
27251 ObjectSize

# jmap -histo 27251 | grep US_ASCII
 145:             1             40  sun.nio.cs.US_ASCII

JDK 1.6.0_31

# java -version
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b04)
Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01, mixed mode)

# java obj.ObjectSize &

# jps | grep ObjectSize
26645 ObjectSize

# jmap -histo 26645 | grep US_ASCII
161:             1             24  sun.nio.cs.US_ASCII

对象大小.java

package obj;
import java.util.concurrent.TimeUnit;
import sun.nio.cs.US_ASCII;

public class ObjectSize {

    public static void main(String[] args) {
        US_ASCII as = new US_ASCII();
        System.out.println(as);

        try {
            TimeUnit.MINUTES.sleep(5);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
4

3 回答 3

5

我认为您所遇到的只是一个源于编译编程语言如何工作的事实,特别是如果它们在 VM 中运行。

允许虚拟机实现的变化表现不同,例如生成不同大小的 Java 字节码——只要它们保持相同的 Java API

内存使用的差异真的那么大吗?如果内存大小的增加实际上是一个问题,我敢建议您首先已经遇到了内存问题。

如果您使用一台虚拟机以 50% 的容量工作,而现在使用另一台虚拟机达到上限,我想您需要对代码进行一些更深入的更改。或者在问题上投入更多的硬件。;)

于 2013-01-08T09:12:26.887 回答
2

支持 Java 6 的早期版本,-XX:+UseCompressedOops但默认情况下它是关闭的。(Java 6 的第一个版本根本不支持这一点)这意味着 64 位 JVM 中的引用是 64 位的。在较新的 JVM 中,如果堆小于 32 GB,则使用 32 位引用。它可以做到这一点,因为对象是 8 字节对齐的,因此您可以使用 32 位引用寻址 2^32 * 8 字节。

注意:US_ASCII 继承了 Charset 的三个字段

private final String name;          // tickles a bug in oldjavac
private final String[] aliases;     // tickles a bug in oldjavac
private Set<String> aliasSet = null;

这些引用小了 4 字节,节省了 12 字节,但是对象是 8 字节对齐的,因此总共节省了 16 字节。

使用压缩的 oops 可以减少使用的内存量。

Hotspot JVM 中的压缩 oops

顺便说一句:你不会直接使用这个类,而是你会使用StandardCharset.US_ASCII

于 2013-01-08T09:23:01.917 回答
1

你有什么建议吗?

如果内存的使用对您很重要,请不要使用 1.6.0_21 的 64 位版本。切换到 32 位版本或更新的补丁级别。或者更好的是,Java 7。毕竟 1.6.0_21 已经过时了。

或者,运行 JVM 并选择显式启用压缩 oops,如下所述

“对于 6u23 版本之前的 JDK 6,在 java 命令中使用 -XX:+UseCompressedOops 标志来启用该功能。”

(但请注意,这可能会引起......当时......仍然是实验性 JVM 功能的错误。)

于 2013-01-08T09:38:22.327 回答