ฉันจะตรวจสอบการใช้งาน CPU และหน่วยความจำใน Java ได้อย่างไร


97

ฉันต้องการตรวจสอบการใช้งาน CPU และหน่วยความจำสำหรับเซิร์ฟเวอร์ใน java มีใครรู้บ้างว่ามันทำได้อย่างไร?


บางทีลิงก์เหล่านี้อาจเป็นประโยชน์: javaworld.com/javaworld/javaqa/2002-11/01-qa-1108-cpu.html roseindia.net/javatutorials/…
chessguy

คำตอบ:


73

หากคุณกำลังมองหาหน่วยความจำโดยเฉพาะใน JVM:

Runtime runtime = Runtime.getRuntime();

NumberFormat format = NumberFormat.getInstance();

StringBuilder sb = new StringBuilder();
long maxMemory = runtime.maxMemory();
long allocatedMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();

sb.append("free memory: " + format.format(freeMemory / 1024) + "<br/>");
sb.append("allocated memory: " + format.format(allocatedMemory / 1024) + "<br/>");
sb.append("max memory: " + format.format(maxMemory / 1024) + "<br/>");
sb.append("total free memory: " + format.format((freeMemory + (maxMemory - allocatedMemory)) / 1024) + "<br/>");

อย่างไรก็ตามควรนำมาเป็นค่าประมาณเท่านั้น ...


ดังนั้นถ้าฉัน runnin ใน Eclipse สิ่งนี้จะขึ้นอยู่กับการตั้งค่า Eclipse ของฉัน?
กาแฟ

4
โปรดทราบว่านี่ไม่ใช่หน่วยความจำที่ใช้จริง - นี่คือ 'หน่วยความจำที่จัดสรร' ซึ่งหมายถึงฮีปที่ java ได้จัดสรรไว้ดังนั้นหากคุณมี -Xms90g และแอปของคุณมีน้ำหนักเบามากคุณจะยังคงได้รับการจัดสรรหน่วยความจำเป็นสิ่งที่มากกว่า 90g . ดูคำตอบโดย "ไม่ทราบ (yahoo)" ที่ถูกลบด้านล่าง (ซึ่งอาจแตกต่างออกไปในตอนแรก)
0fnt

แค่อยากรู้ว่าทำไมสิ่งเหล่านี้จึงเป็นเพียงการประมาณเท่านั้น?
ComputerScientist

@ComputerScientist เนื่องจากฟรีคือสิ่งที่ฟรี (โพสต์ GC) จึงไม่แสดงวัตถุที่รอ GC เพื่อให้ถูกต้องมากขึ้นให้เรียกใช้คอลเล็กชันขยะ 2 ชุดก่อนคำตอบนี้ หากคุณลองใช้และไม่มี GC คุณจะพบว่าค่า post-GC สอดคล้องกันมาก แต่โดยทั่วไปแล้วค่า preGC จะมีค่าอย่างน้อยสองเท่า
Bill K

@sbeliakov คุณสามารถใช้ JavaSysmon ( github.com/jezhumble/javasysmon ) แม้ว่าฉันจะแนะนำให้คุณเปิดคำถามใหม่และฉันจะตอบ ไลบรารีบน GitHub มีข้อบกพร่องและรับรู้ 32 บิตเป็น 64 บิต แต่ฉันพบวิธีแก้ปัญหาเกี่ยวกับการผสมขวดต่างๆ [ github.com/goxr3plus/XR3Player/blob/master/resources/libs/… ]
GOXR3PLUS

20
package mkd.Utils;

import java.io.File;
import java.text.NumberFormat;

public class systemInfo {

    private Runtime runtime = Runtime.getRuntime();

    public String Info() {
        StringBuilder sb = new StringBuilder();
        sb.append(this.OsInfo());
        sb.append(this.MemInfo());
        sb.append(this.DiskInfo());
        return sb.toString();
    }

    public String OSname() {
        return System.getProperty("os.name");
    }

    public String OSversion() {
        return System.getProperty("os.version");
    }

    public String OsArch() {
        return System.getProperty("os.arch");
    }

    public long totalMem() {
        return Runtime.getRuntime().totalMemory();
    }

    public long usedMem() {
        return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
    }

    public String MemInfo() {
        NumberFormat format = NumberFormat.getInstance();
        StringBuilder sb = new StringBuilder();
        long maxMemory = runtime.maxMemory();
        long allocatedMemory = runtime.totalMemory();
        long freeMemory = runtime.freeMemory();
        sb.append("Free memory: ");
        sb.append(format.format(freeMemory / 1024));
        sb.append("<br/>");
        sb.append("Allocated memory: ");
        sb.append(format.format(allocatedMemory / 1024));
        sb.append("<br/>");
        sb.append("Max memory: ");
        sb.append(format.format(maxMemory / 1024));
        sb.append("<br/>");
        sb.append("Total free memory: ");
        sb.append(format.format((freeMemory + (maxMemory - allocatedMemory)) / 1024));
        sb.append("<br/>");
        return sb.toString();

    }

    public String OsInfo() {
        StringBuilder sb = new StringBuilder();
        sb.append("OS: ");
        sb.append(this.OSname());
        sb.append("<br/>");
        sb.append("Version: ");
        sb.append(this.OSversion());
        sb.append("<br/>");
        sb.append(": ");
        sb.append(this.OsArch());
        sb.append("<br/>");
        sb.append("Available processors (cores): ");
        sb.append(runtime.availableProcessors());
        sb.append("<br/>");
        return sb.toString();
    }

    public String DiskInfo() {
        /* Get a list of all filesystem roots on this system */
        File[] roots = File.listRoots();
        StringBuilder sb = new StringBuilder();

        /* For each filesystem root, print some info */
        for (File root : roots) {
            sb.append("File system root: ");
            sb.append(root.getAbsolutePath());
            sb.append("<br/>");
            sb.append("Total space (bytes): ");
            sb.append(root.getTotalSpace());
            sb.append("<br/>");
            sb.append("Free space (bytes): ");
            sb.append(root.getFreeSpace());
            sb.append("<br/>");
            sb.append("Usable space (bytes): ");
            sb.append(root.getUsableSpace());
            sb.append("<br/>");
        }
        return sb.toString();
    }
}

ความเข้าใจของฉันว่าหัวข้อเริ่มต้นคือถามเกี่ยวกับจำนวนหน่วยความจำที่มีอยู่ใน OS freeMemoryที่นี่ส่งคืนจำนวนหน่วยความจำที่มีอยู่ใน JVM ซึ่งแตกต่างกันมาก
Tagar

ไม่แปลกที่คลาสของคุณ SystemInfo ไม่ได้ขึ้นต้นด้วย Capital และวิธีการของคุณ Info (), OSname (), MemInfo () ทำ?
Drswaki69

18

หากคุณกำลังใช้ Sun JVM และสนใจการใช้งานหน่วยความจำภายในของแอปพลิเคชัน (จำนวนหน่วยความจำที่แอปของคุณใช้อยู่) ฉันต้องการเปิดการบันทึกการรวบรวมขยะในตัวของ JVM คุณเพียงแค่เพิ่ม -verbose: gc ในคำสั่งเริ่มต้น

จากเอกสาร The Sun:

อาร์กิวเมนต์บรรทัดคำสั่ง -verbose: gc พิมพ์ข้อมูลในทุกคอลเลกชัน โปรดทราบว่ารูปแบบของเอาต์พุต -verbose: gc อาจเปลี่ยนแปลงได้ระหว่างรีลีสของแพลตฟอร์ม J2SE ตัวอย่างเช่นนี่คือผลลัพธ์จากแอ็พพลิเคชันเซิร์ฟเวอร์ขนาดใหญ่:

[GC 325407K->83000K(776768K), 0.2300771 secs]
[GC 325816K->83372K(776768K), 0.2454258 secs]
[Full GC 267628K->83769K(776768K), 1.8479984 secs]

ที่นี่เราจะเห็นคอลเล็กชันย่อยสองคอลเลคชันและหนึ่งคอลเล็กชันหลัก ตัวเลขก่อนและหลังลูกศร

325407K->83000K (in the first line)

ระบุขนาดรวมของวัตถุที่มีชีวิตก่อนและหลังการเก็บขยะตามลำดับ หลังจากการรวบรวมเล็กน้อยการนับรวมถึงวัตถุที่ไม่จำเป็นต้องมีชีวิต แต่ไม่สามารถเรียกคืนได้ไม่ว่าจะเป็นเพราะพวกมันมีชีวิตโดยตรงหรือเป็นเพราะอยู่ภายในหรืออ้างอิงจากรุ่นที่ครอบครอง ตัวเลขในวงเล็บ

(776768K) (in the first line)

คือพื้นที่ว่างทั้งหมดโดยไม่นับพื้นที่ในการสร้างแบบถาวรซึ่งเป็นจำนวนฮีปทั้งหมดลบหนึ่งในช่องว่างของผู้รอดชีวิต การรวบรวมเล็กน้อยใช้เวลาประมาณหนึ่งในสี่ของวินาที

0.2300771 secs (in the first line)

ดูข้อมูลเพิ่มเติมได้ที่: http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html


17

จากที่นี่

    OperatingSystemMXBean operatingSystemMXBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
    RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
    int availableProcessors = operatingSystemMXBean.getAvailableProcessors();
    long prevUpTime = runtimeMXBean.getUptime();
    long prevProcessCpuTime = operatingSystemMXBean.getProcessCpuTime();
    double cpuUsage;
    try
    {
        Thread.sleep(500);
    }
    catch (Exception ignored) { }

    operatingSystemMXBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
    long upTime = runtimeMXBean.getUptime();
    long processCpuTime = operatingSystemMXBean.getProcessCpuTime();
    long elapsedCpu = processCpuTime - prevProcessCpuTime;
    long elapsedTime = upTime - prevUpTime;

    cpuUsage = Math.min(99F, elapsedCpu / (elapsedTime * 10000F * availableProcessors));
    System.out.println("Java CPU: " + cpuUsage);

1
แล้วเรื่องความจำล่ะ?
Daniel De León

2
รายการ <MemoryPoolMXBean> memoryPools = ArrayList ใหม่ <MemoryPoolMXBean> (ManagementFactory.getMemoryPoolMXBeans ()); long usedHeapMemoryAfterLastGC = 0; สำหรับ (MemoryPoolMXBean memoryPool: memoryPools) {if (memoryPool.getType (). เท่ากับ (MemoryType.HEAP)) {MemoryUsage poolCollectionMemoryUsage = memoryPool.getCollectionUsage (); usedHeapMemoryAfterLastGC + = poolCollectionMemoryUsage.getUsed (); }}
danieln

1
ขอบคุณสำหรับคำตอบเดียวที่แสดงการดึงการใช้งาน CPU
Matthieu

1
อะไรคือความแตกต่างระหว่างการทำเช่นนี้กับการทำง่ายๆoperatingSystemMXBean.getProcessCpuLoad();? ตามเอกสารของ Oracle วิธีนี้จะส่งคืน "ส่งคืน" การใช้งาน cpu ล่าสุด "สำหรับกระบวนการ Java Virtual Machine" แต่ฉันเห็นความแตกต่างระหว่างวิธีของคุณกับวิธีนี้ค่อนข้างมาก
Ishnark

1
@RobHall มีสองOperatingSystemMXBeanคลาส หนึ่งคืออินเทอร์เฟซที่มีให้ในjava.lang. com.sun.managementแต่ยังมีอีกรุ่นหนึ่งที่ขยายในเรื่องนี้ นั่นคือวิธีการที่ฉันอ้างถึงคือจากนั้นOperatingSystemMXBean
Ishnark

9

JMX, MXBeans (ThreadMXBean ฯลฯ ) ที่ให้มาจะให้การใช้งานหน่วยความจำและ CPU แก่คุณ

OperatingSystemMXBean operatingSystemMXBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
operatingSystemMXBean.getSystemCpuLoad();

8

สำหรับการใช้งานหน่วยความจำสิ่งต่อไปนี้จะใช้งานได้

long total = Runtime.getRuntime().totalMemory();
long used  = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

สำหรับการใช้งาน CPU คุณจะต้องใช้แอปพลิเคชันภายนอกเพื่อวัดผล


6

เนื่องจาก Java 1.5 JDK มาพร้อมกับเครื่องมือใหม่: JConsole ซึ่งสามารถแสดงการใช้งาน CPU และหน่วยความจำของ JVM 1.5 หรือใหม่กว่าได้ มันสามารถทำแผนภูมิของพารามิเตอร์เหล่านี้ส่งออกเป็น CSV แสดงจำนวนคลาสที่โหลดจำนวนอินสแตนซ์การหยุดชะงักเธรด ฯลฯ ...


4

หากคุณใช้โซลูชัน runtime / totalMemory ที่มีการโพสต์ในคำตอบมากมายที่นี่ (ฉันทำมามากแล้ว) อย่าลืมบังคับให้รวบรวมขยะสองชุดก่อนหากคุณต้องการผลลัพธ์ที่ค่อนข้างแม่นยำ / สอดคล้องกัน

สำหรับประสิทธิภาพ Java มักจะอนุญาตให้ขยะเติมหน่วยความจำทั้งหมดก่อนที่จะบังคับให้ GC และถึงแม้จะไม่ใช่ GC ที่สมบูรณ์ดังนั้นผลลัพธ์ของคุณสำหรับ runtime.freeMemory () จะอยู่ที่ใดที่หนึ่งระหว่างจำนวนหน่วยความจำว่าง "จริง" กับ 0 เสมอ .

GC แรกไม่ได้รับทุกอย่าง แต่ได้รับประโยชน์สูงสุด

การแกว่งขึ้นก็คือถ้าคุณโทรไปที่ freeMemory () คุณจะได้หมายเลขที่ไร้ประโยชน์และแตกต่างกันไป แต่ถ้าทำ 2 gc ก่อนมันเป็นมาตรวัดที่น่าเชื่อถือมาก นอกจากนี้ยังทำให้กิจวัตรประจำวันช้าลงมาก (อาจเป็นวินาที)



2

JConsoleเป็นวิธีง่ายๆในการตรวจสอบแอปพลิเคชัน Java ที่ทำงานอยู่หรือคุณสามารถใช้ Profiler เพื่อรับข้อมูลรายละเอียดเพิ่มเติมเกี่ยวกับแอปพลิเคชันของคุณ ฉันชอบใช้NetBeans Profilerสำหรับสิ่งนี้


2

นี่คือรหัสง่ายๆในการคำนวณการใช้หน่วยความจำปัจจุบันเป็นเมกะไบต์:

double currentMemory = ( (double)((double)(Runtime.getRuntime().totalMemory()/1024)/1024))- ((double)((double)(Runtime.getRuntime().freeMemory()/1024)/1024));

2

ฉันจะเพิ่มวิธีต่อไปนี้เพื่อติดตามการโหลด CPU:

import java.lang.management.ManagementFactory;
import com.sun.management.OperatingSystemMXBean;

double getCpuLoad() {
    OperatingSystemMXBean osBean =
        (com.sun.management.OperatingSystemMXBean) ManagementFactory.
        getPlatformMXBeans(OperatingSystemMXBean.class);
    return osBean.getProcessCpuLoad();
}

คุณสามารถอ่านเพิ่มเติมได้ที่นี่




โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.