JVM直接内存

JVM直接内存测试
测试代码如下:

导入这两个包


import com.sun.management.OperatingSystemMXBean;
import sun.nio.ch.DirectBuffer;

有可能引起IDE报错

Eclipse 默认把这些受访问限制的API设成了ERROR。
Windows -> Preferences -> Java -> Compiler -> Errors/Warnings ->
Deprecated and trstricted API -> Forbidden reference (access rules): -> change to warning


import java.lang.management.ManagementFactory;
import java.lang.management.MemoryUsage;
import java.lang.management.RuntimeMXBean;
import java.nio.ByteBuffer;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import com.sun.management.OperatingSystemMXBean;
import sun.nio.ch.DirectBuffer;

public class TestDirectMemory {

    public static void main(String[] args) throws InterruptedException {

        System.out.println("之前的内存占用:" + getMemoryLog());
        //分配1G直接内存
        ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 * 1024);

        System.out.println("之后的内存占用:" + getMemoryLog());

    }

    public static String getMemoryLog() {
        OperatingSystemMXBean osmxb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
        // 当前使用的内存(堆内存和非堆内存)
        long totalMemory = Runtime.getRuntime().totalMemory();
        // 剩余内存
        long freeMemory = Runtime.getRuntime().freeMemory();
        // JVM最大可使用内存
        long maxMemory = Runtime.getRuntime().maxMemory();
        // 总的物理内存
        long totalMemorySize = osmxb.getTotalPhysicalMemorySize();
        // 剩余的物理内存
        long freePhysicalMemorySize = osmxb.getFreePhysicalMemorySize();
        // 已使用的物理内存
        long usedMemory = (osmxb.getTotalPhysicalMemorySize() - osmxb.getFreePhysicalMemorySize());

        RuntimeMXBean runtimeMBean = (RuntimeMXBean) ManagementFactory.getRuntimeMXBean();
        long prevUpTime = runtimeMBean.getUptime();
        long prevProcessCpuTime = osmxb.getProcessCpuTime();
        try {
            TimeUnit.MILLISECONDS.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        StringBuffer sb = new StringBuffer();
        sb.append("|内存|当前使用的内存:" + size2str(totalMemory));
        sb.append("|剩余内存:" + size2str(freeMemory));
        sb.append("|最大可使用内存:" + size2str(maxMemory));
        sb.append("|总的物理内存:" + size2str(totalMemorySize));
        sb.append("|剩余的物理内存:" + size2str(freePhysicalMemorySize));
        sb.append("|已使用的物理内存:" + size2str(usedMemory));
        MemoryUsage heap = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();

        MemoryUsage none = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();

        sb.append("|堆:" + size2str(heap.getUsed()) + "/" + size2str(heap.getMax()));
        sb.append("|非堆:" + size2str(none.getUsed()) + "/" + size2str(none.getMax()));

        int nCPUs = osmxb.getAvailableProcessors();
        long uptime = runtimeMBean.getUptime();
        long processCpuTime = osmxb.getProcessCpuTime();
        long elapsedCpu = processCpuTime - prevProcessCpuTime;
        long elaspedTime = uptime - prevUpTime;
        float cpuUsage = elapsedCpu / (elaspedTime * 10000F * nCPUs);
        sb.append("|Cpu使用率:" + cpuUsage);

        if (freeMemory < (totalMemory / 20)) {
            sb.append(",警告,内存空间小于:" + freeMemory + "MB");
        }

        return sb.toString();
    }

    public static final long ONE_KB = 1024;

    public static final long ONE_MB = ONE_KB * ONE_KB;

    public static final long ONE_GB = ONE_KB * ONE_MB;

    public static String size2str(long size) {
        StringBuilder builder = new StringBuilder();
        if (size / ONE_GB > 0) {
            builder.append(size / ONE_GB).append("G ");
            builder.append(size2str(size % ONE_GB));
        } else if (size / ONE_MB > 0) {
            builder.append(size / ONE_MB).append("M ");
            builder.append(size2str(size % ONE_MB));
        } else if (size / ONE_KB > 0) {
            builder.append(size / ONE_KB).append("K ");
            builder.append(size2str(size % ONE_KB));
        } else {
            builder.append(size).append("bytes");
        }
        return builder.toString();
    }

}

测试1:
JVM参数:

-Xmx100m
输出:

之前的内存占用:|内存|当前使用的内存:96M 0bytes|剩余内存:93M 966K 400bytes|最大可使用内存:96M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:3G 335M 432K 0bytes|已使用的物理内存:4G 588M 672K 0bytes|堆:2M 57K 624bytes/96M 0bytes|非堆:3M 42K 760bytes/130M 0bytes|Cpu使用率:0.0

Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
    at java.nio.Bits.reserveMemory(Bits.java:658)
    at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
    at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306)
    at TestDirectMemory.main(TestDirectMemory.java:21)

结果:

运行异常,因为如果没设置-XX:MaxDirectMemorySize,则默认与-Xmx参数值相同,分配1G直接内存超出限制范围。
测试2:
JVM参数:

-Xmx2G
输出:

之前的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:118M 921K 184bytes|最大可使用内存:1G 796M 512K 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:3G 264M 880K 0bytes|已使用的物理内存:4G 659M 224K 0bytes|堆:2M 614K 840bytes/1G 796M 512K 0bytes|非堆:3M 42K 952bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:118M 921K 184bytes|最大可使用内存:1G 796M 512K 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:2G 272M 400K 0bytes|已使用的物理内存:5G 651M 704K 0bytes|堆:2M 614K 840bytes/1G 796M 512K 0bytes|非堆:3M 73K 520bytes/130M 0bytes|Cpu使用率:0.0
结果:

运行正常,因为1G小于2G,属于范围内分配。很明显可以看出来,物理内存少了1G
测试3:
JVM参数:

-Xmx1G -XX:MaxDirectMemorySize=512M
输出:

之前的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:118M 921K 104bytes|最大可使用内存:910M 512K 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:3G 274M 428K 0bytes|已使用的物理内存:4G 649M 676K 0bytes|堆:2M 614K 920bytes/910M 512K 0bytes|非堆:3M 42K 696bytes/130M 0bytes|Cpu使用率:0.0

Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
    at java.nio.Bits.reserveMemory(Bits.java:658)
    at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
    at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:306)
    at TestDirectMemory.main(TestDirectMemory.java:21)

结果:

运行异常,分配的直接内存1G超过限定的521M
测试4:
代码修改如下:

        System.out.println("之前的内存占用:" + getMemoryLog());
        //分配1G直接内存
        ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 * 1024);

        System.out.println("之后的内存占用1:" + getMemoryLog());

        //清除直接缓存
        ((DirectBuffer)bb).cleaner().clean();

        System.out.println("之后的内存占用2:" + getMemoryLog());

JVM参数:


输出:

之前的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:3G 264M 356K 0bytes|已使用的物理内存:4G 659M 748K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 9K 632bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用1:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:2G 270M 904K 0bytes|已使用的物理内存:5G 653M 200K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 40K 24bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用2:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:3G 258M 148K 0bytes|已使用的物理内存:4G 665M 976K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 40K 24bytes/130M 0bytes|Cpu使用率:0.0
结果:

很明显,内存得到了释放
测试5:

测试一下会不会被system.gc()
代码修改如下:

        System.out.println("之前的内存占用:" + getMemoryLog());
        //分配1G直接内存
        ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 * 1024);

        System.out.println("之后的内存占用1:" + getMemoryLog());

        System.gc();

        System.out.println("之后的内存占用2:" + getMemoryLog());

JVM参数:


输出:

之前的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:3G 262M 1008K 0bytes|已使用的物理内存:4G 661M 96K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 9K 520bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用1:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:2G 269M 896K 0bytes|已使用的物理内存:5G 654M 208K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 39K 936bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用2:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:120M 318K 1000bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:2G 268M 648K 0bytes|已使用的物理内存:5G 655M 456K 0bytes|堆:1M 858K 736bytes/1G 775M 0bytes|非堆:3M 38K 1016bytes/130M 0bytes|Cpu使用率:0.0
结果:

虽然强制调用了sytem.gc() 但是因为堆状况良好,所以没有被回收
测试6

测试一下会不会被JVM自动回收掉
代码修改如下:

        System.out.println("之前的内存占用:" + getMemoryLog());
        //分配1G直接内存
        ByteBuffer bb = ByteBuffer.allocateDirect(1024 * 1024 * 1024);

        for(;;){
            System.out.println("之后的内存占用:" + getMemoryLog());
            TimeUnit.SECONDS.sleep(1);
        }

JVM参数:


输出:

之前的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:3G 272M 404K 0bytes|已使用的物理内存:4G 651M 700K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 9K 496bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:2G 280M 12K 0bytes|已使用的物理内存:5G 644M 68K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 40K 16bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:2G 280M 0bytes|已使用的物理内存:5G 644M 80K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 40K 16bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:2G 283M 804K 0bytes|已使用的物理内存:5G 640M 300K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 40K 16bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:2G 282M 184K 0bytes|已使用的物理内存:5G 641M 920K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 40K 16bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:2G 285M 0bytes|已使用的物理内存:5G 639M 80K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 40K 16bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:2G 289M 244K 0bytes|已使用的物理内存:5G 634M 860K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 40K 16bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:2G 290M 100K 0bytes|已使用的物理内存:5G 633M 1004K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 40K 16bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:2G 290M 268K 0bytes|已使用的物理内存:5G 633M 836K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 40K 16bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:2G 292M 188K 0bytes|已使用的物理内存:5G 631M 916K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 40K 16bytes/130M 0bytes|Cpu使用率:0.0

之后的内存占用:|内存|当前使用的内存:121M 512K 0bytes|剩余内存:119M 562K 736bytes|最大可使用内存:1G 775M 0bytes|总的物理内存:7G 924M 80K 0bytes|剩余的物理内存:2G 291M 536K 0bytes|已使用的物理内存:5G 632M 568K 0bytes|堆:1M 973K 288bytes/1G 775M 0bytes|非堆:3M 40K 16bytes/130M 0bytes|Cpu使用率:0.0
结果:

我们看到很长的一段时间内,内存一直没有得到释放

猜你喜欢

转载自watersrc.iteye.com/blog/2345036