从一个例子看JVM启动过程(2)

其实,在代码执行到Main函数之前,需要加载初始化很多类。在初始化虚拟机的这段时间中,Bits类先于VM类初始化,即在VM还没有初始化完的时候,Bits类就已经开始初始化静态属性maxMemory,而通过反射拿到的值也是这个时候设置的值。具体过程如下:
private static volatile long maxMemory = VM.maxDirectMemory();
public static long maxDirectMemory() {
     //这个时候VM还没初始化好,跳过此分支 
  if (booted)
            return directMemory;

        Properties p = System.getProperties();
        String s = (String)p.remove("sun.nio.MaxDirectMemorySize");
        System.setProperties(p);
//因为System也未初始化好,所以s==null。跳过此分支。        
if (s != null) {
            if (s.equals("-1")) {
                // -XX:MaxDirectMemorySize not given, take default
                directMemory = Runtime.getRuntime().maxMemory();
            } else {
                long l = Long.parseLong(s);
                if (l > -1)
                    directMemory = l;
            }
        }
//直接返回directMemory属性
        return directMemory;
    }

而VM的directMemory属性的值呢
  
 private static long directMemory = 64 * 1024 * 1024;

也就是所看到的maxMemoryValue:67108864了。这也是会把NIO的directByteBuffer的默认值认为是64M的原因了。事实并非如此:
System类的在初始化的时候会再次执行VM.maxDirectMemory(),
// Set the maximum amount of direct memory.  This value is controlled
// by the vm option -XX:MaxDirectMemorySize=<size>.  This method acts
// as an initializer only if it is called before sun.misc.VM.booted().
        sun.misc.VM.maxDirectMemory();
这个时候的Properties已经准备好了。就会走上面if (s != null) 分支,如果有设定就会把值设定为预先设定的值。如果没有设定就会Runtime.getRuntime().maxMemory(),该方法返回的就是当前JVM最大可用的内存(不是-xmx指定的那个值,而是-xmx的值减去一个survivor区的值,因为2个survivor总有个survivor是空的,不能算在可用空间里的)。做完这个之后,会把VM类的booted属性置为true。最后获得的maxDirectMemory就是这个值。


这篇博客是对http://hllvm.group.iteye.com/group/topic/28866 讨论贴的一个总结,同时感谢R大http://rednaxelafx.iteye.com/ 不厌其烦的为我解惑。

你可能感兴趣的:(jvm)