Package jdk.management.resource

Resource tracking contexts, meters, and factories. The resource tracking package provides the basic framework and implementation to track resource use.

The architecture identifies three major components:

  • Resource Tracking API - provides a context for resource meters and binding threads to each ResourceContext.
  • Resource instrumentation - implements the hooks in specific Java Runtime subsystems to gather information, request resource approvals and apply the mechanisms to allow, limit, or deny resource access. The instrumentation of each resource dynamically locates the ResourceContext associated with the calling thread and forwards the ResourceRequest to the matching ResourceType. Resources used by native libraries or the virtual machine such as file descriptors or sockets are neither instrumented nor tracked. The resources instrumented include:
    • FileDescriptors - open file descriptor count, totals
      • FileDescriptors associated with explicit files
      • FileDescriptors associated with sockets and socket channels
    • Files - open file count, bytes sent, bytes received, totals
      • FileInputStream, FileOutputStream, RandomAccessFile
      • NIO synchronous and asynchronous FileChannels
      • Standard streams System.err, System.in, System.out
    • Sockets and datagrams - open socket count, bytes sent, bytes received, datagrams sent, datagrams received, totals
      • Socket, ServerSocket, DatagramSocket
      • NIO SocketChannel and DatagramChannel
      • NIO AsynchronousSocketChannel
    • Heap - allocated and retained bytes, total allocations
    • Threads - active thread count, CPU time per resource context
  • Resource Manager - the trusted external entity that monitors resource usage and implements a resource policy. The resource manager binds resource consumer threads in the application domain with a ResourceContext. A resource manager and resource management policy are not included.

Resource management is a security sensitive API and access to the API is allowed by a SecurityManager, if any, and the RuntimePermission("jdk.management.resource.getResourceContextFactory").

Resource tracking is enabled via the command line options -XX:+ResourceManagement and -XX:ResourceManagementSampleInterval=nn (milliseconds) and -XX:+UseG1GC as appropriate to provide retained heap amounts.

Resource Accounting and Threading

For library based resources, the thread that is consuming the resource, opening files, reading streams, etc. is used to measure and record the use in ResourceMeters. The instrumentation is accomplished by interposing on the common public APIs to record the activity.

The use of the application thread is sensitive. The resource manager must not interfere with the application and must avoid calling functions that might cause recursive calls to the resource management instrumentation. Implementations of the ResourceRequest and ResourceApprover interfaces must be kept short, lightweight and be self contained. Calls through these interfaces occur very frequently and can impact performance of all instrumented resources. For example, calling System.out.println to insert debugging output results in a recursive call. It can cause unintentional loops and/or be a victim of incomplete class initialization. Symptoms may include StackOverflowError or ExceptionInInitializerError.

For resource allocation, the updates to the meters usually occur before the action is performed to allow the resource manager policy to slow or deny use of the resource. The release of resources happens after the resources are released so the resource counts are not prematurely decremented. For resources that have been allocated but not used, the remainder is released. For example, if a SecurityException occurs on opening a file, the count of open file count is reduced, or if when reading a file, if the amount of data read from the file is less than requested, the bytes not read reduce the count.

File Resource Tracking

Resources used to open, read and write files are tracked for the classes AsynchronousFileChannel, FileChannel, FileInputStream, FileOutputStream, and RandomAccessFile. The ResourceId reported is the pathname provided to the API except for AsynchronousFileChannel where it is the FileDescriptor number or handle. The methods below are instrumented to accumulate the resource usage to the indicated ResourceMeters using the thread of the application. The resource consumption can be denied by the ResourceApprover or ResourceMeter by returning zero or throwing a ResourceRequestDeniedException. When denied, the I/O operation fails with an IOException.

When a file is opened the ResourceContext is remembered until it is closed. The close of the channel or file reduces the count in the same ResourceContext that opened it.

File Resource Tracking
ResourceType Incremented Decremented Amount
FILE_OPEN AsynchronousFileChannel.open,
FileChannel.open,
FileInputStream,
FileOutputStream,
RandomAccessFile
AsynchronousFileChannel.close,
FileChannel.close,
FileInputStream.close,
FileOutputStream.close,
RandomAccessFile.close
1
FILE_READ AsynchronousFileChannel.read,
FileChannel.read,
FileInputStream.read,
RandomAccessFile.read methods,
System.in.read
requested number of bytes to read less number actually read length
FILE_WRITE AsynchronousFileChannel.write,
FileChannel.write,
FileOutputStream.write,
RandomAccessFile.write methods,
System.err print and write methods,
System.out print and write methods
Exception length

File Descriptor Tracking

Resources used by file descriptors to open channels, files, and sockets are tracked. Resource requests to allocate file descriptors do not necessarily provide the ResourceId of the file descriptor because the resource check may occur before the file descriptor is determined. If available however, the file descriptor number or handler is used as the name of the ResourceId. The methods below are instrumented to accumulate the resource usage to the indicated ResourceMeters using the thread of the application. The resource consumption can be denied by the ResourceApprover or ResourceMeter by returning zero or throwing a ResourceRequestDeniedException. When denied, the I/O operation fails with an IOException.

When a file descriptor is allocated the ResourceContext is remembered until it is closed. The close of the file descriptor reduces the count in the same ResourceContext that opened it.

File Descriptor Resource Tracking
ResourceType Incremented Decremented Amount
FILEDESCRIPTOR_OPEN AsynchronousFileChannel.open,
AsynchronousServerSocketChannel.accept,
AsynchronousServerSocketChannel.open,
AsynchronousSocketChannel.open,
DatagramChannel.open,
DatagramSocket,
FileChannel.open,
FileInputStream,
FileOutputStream,
RandomAccessFile,
ServerSocketChannel.accept,
ServerSocketChannel.open,
ServerSocket (if binding),
ServerSocket.accept,
ServerSocket.bind (if not bound),
Socket (if connecting),
Socket.connect (if not connected)
SocketChannel.open
AsynchronousFileChannel.close,
AsynchronousServerSocketChannel.close,
AsynchronousSocketChannel.close,
DatagramChannel.close,
DatagramSocket.close,
FileChannel.close,
FileInputStream.close,
FileOutputStream.close,
RandomAccessFile.close,
ServerSocketChannel.close,
ServerSocket.close,
Socket.close,
SocketChannel.close
1

In the foregoing, note that the resource count is updated when the corresponding native analog of the file descriptor is either allocated or closed. For ServerSockets and Sockets this occurs when the socket is bound or connected, respectively. Binding or connecting may occur either during instantiation of the socket or subsequent thereto.

Socket Resource Tracking

Resources used to open, send and receive data over sockets are tracked for sockets and socket channels, datagram sockets and datagram channels, and asynchronous socket channels. Note that this includes SSL server and client sockets. The ResourceId reported is the address of the local network port. The methods below are instrumented to accumulate the resource usage to the indicated ResourceMeters using the thread of the application. The resource consumption can be denied by the ResourceApprover or ResourceMeter by returning zero or throwing a ResourceRequestDeniedException. When denied, the I/O operation fails with an IOException.

When a socket is opened the ResourceContext is remembered until it is closed. The close of the channel socket reduces the count in the same ResourceContext that opened it.

Socket Resource Consumption Tracking
ResourceType Incremented Decremented Amount
SOCKET_OPEN AsynchronousServerSocketChannel.accept,
AsynchronousServerSocketChannel.bind (if not bound),
AsynchronousSocketChannel.bind (if not bound),
AsynchronousSocketChannel.connect (if not bound),
ServerSocketChannel.bind (if not bound),
ServerSocket.accept,
ServerSocket.bind (if not bound),
Socket.bind (if not bound),
Socket.connect (if not bound),
SocketChannel.bind (if not bound),
SocketChannel.connect (if not bound)
AsynchronousServerSocketChannel.close,
AsynchronousSocketChannel.close,
ServerSocketChannel.close,
ServerSocket.close,
Socket.close,
SocketChannel.close
1
SOCKET_READ AsynchronousSocketChannel.read,
Socket.getInputStream().read,
SocketChannel.read
requested number of bytes to read less number actually read length
SOCKET_WRITE AsynchronousSocketChannel.write,
Socket.getOutputStream().write,
SocketChannel.write
Exception length

In the foregoing, note that incrementing the SOCKET_OPEN resource count occurs when the object is bound, not when it is created. Binding may occur while connecting if the socket was not previously bound.

Datagram Resource Tracking

Resources used to open, send and receive datagrams are tracked for the DatagramChannel and DatagramSocket classes. The ResourceId reported is the address of the local network port. The methods below are instrumented to accumulate the resource usage to the indicated ResourceMeters using the thread of the application. The resource consumption can be denied by the ResourceApprover or ResourceMeter by returning zero or throwing a ResourceRequestDeniedException. When denied, the I/O operation fails with an IOException.

When a DatagramSocket is opened the ResourceContext is remembered until it is closed. The close of the channel or socket reduces the count in the same ResourceContext that opened it.

Datagram Resource Consumption Tracking
ResourceType Incremented Decremented Amount
DATAGRAM_OPEN DatagramChannel.bind,
DatagramChannel.connect,
DatagramChannel.send,
DatagramSocket.bind,
DatagramSocket.connect,
DatagramChannel.close,
DatagramSocket.close
1
DATAGRAM_RECEIVED DatagramChannel.read,
DatagramChannel.receive,
DatagramSocket.receive
Exception 1
DATAGRAM_SENT DatagramChannel.send,
DatagramChannel.write,
DatagramSocket.send
Exception 1
DATAGRAM_READ DatagramChannel.read,
DatagramChannel.receive,
DatagramSocket.receive
requested number of bytes to read less number actually read +datagram length
DATAGRAM_WRITE DatagramChannel.send,
DatagramChannel.write,
DatagramSocket.send
Exception +datagram length

In the foregoing, note that incrementing the DATAGRAM_OPEN resource count occurs when the object is bound, not when it is created. Binding may occur while connecting or, in the case of DatagramChannel, while sending, if the socket was not previously bound.

Thread Resource Tracking

Thread resources are tracked by monitoring threads and reporting to the ResourceMeters in the ResourceContext bound to the threads. When threads are created and exit, THREAD_CREATED meters are updated. Thread creation is prevented if an exception is thrown. If the amount returned from the meter is zero, a ResourceRequestDeniedException is thrown.

When a thread is unbound from a ResourceContext, the accumulated CPU time usage since the thread was bound to the context is applied to the THREAD_CPU ResourceMeter in the ResourceContext bound to the thread. The update is performed using the thread being unbound.

Threads that are not system threads are initially bound to the unassignedContext. New threads are implicitly bound to the ResourceContext of the thread invoking new Thread. The Thread's Runnable should explicitly bind to the desired context as required.

Periodic updates are performed by a monitoring thread that samples the threads active in each ResourceContext and performs an update for the CPU time of each thread. The ResourceApprover or ResourceMeter actions may return zero or throw ResourceRequestDeniedException but it is platform specific whether it has any effect on the application consuming the resource. The timing of updates may vary due to sampling. The normal behavior of setting granularity of a THREAD_CPU meter applies, notifications occur when crossing granularity boundaries. The sample interval is set by the implementation using the command line switch -XX:ResourceManagementSampleInterval=nn. The default is to sample every 100 milliseconds (.1 second). The sampling can be disabled by providing an argument of 0 (zero). If the argument is less than zero, the default is used.

The ResourceId reported for THREAD_CREATED and THREAD_CPU is the threadID formatted as in Long.toString(threadID).

When a thread is created the ResourceContext is remembered until it exits. The exit of the thread reduces the count of created threads in the same ResourceContext that opened it.

CPU Resource Tracking
ResourceType Incremented Decremented Amount
THREAD_CPU Threads running never nanoseconds
THREAD_CREATED Thread construction Thread exit count

Heap Resource Tracking

Heap Resources are tracked by monitoring threads and garbage collector activity and reporting usage to the ResourceMeters in the ResourceContext bound to the threads.

When a thread is unbound from a ResourceContext, the accumulated heap allocation usage since the thread was bound to the context is applied to the HEAP_ALLOCATED ResourceMeter in the ResourceContext bound to the thread. The update is performed using the thread being unbound. The HEAP_ALLOCATED value sample interval is the same as the THREAD_CPU meter. The ResourceId is the threadId for HEAP_ALLOCATED and is reported for each thread individually.

For HEAP_RETAINED usage, updates occur as the result of garbage collector activity. When a GC phase completes, the meters for HEAP_RETAINED are updated. The accuracy of the retained heap amounts are available from the ResourceId.getAccuracy method as a ResourceAccuracy value. The ResourceApprover or ResourceMeter actions may return zero or throw ResourceRequestDeniedException but it is platform specific whether it has any effect on the application consuming the resource. HEAP_RETAINED updates with ResourceAccuracy.HIGH or ResourceAccuracy.HIGHEST are always delivered without regard to the granularity set on the meter. The timing of updates may vary due to sampling and GC behavior. The ResourceId for HEAP_RETAINED is "Heap".

Heap Resource Tracking
ResourceType Incremented Decremented Amount
HEAP_ALLOCATED Object allocation never bytes allocated (upper bound)
HEAP_RETAINED On GC phase completion On GC phase completion bytes retained (upper bound)

Example using a SimpleMeter to count the bytes written with FileOutputStream


    void test1() {
        ResourceContextFactory rfactory = ResourceContextFactory.getInstance();
        ResourceContext rc1 = rfactory.create("context1");
        ResourceMeter writeMeter = SimpleMeter.create(ResourceType.FILE_WRITE);
        rc1.addResourceMeter(writeMeter);
        rc1.bindThreadContext();

        try {
            long bytesWritten = writeFile("example1.tmp");
            assert bytesWritten == writeMeter.get() : "Expected: " + bytesWritten + ", actual: " + writeMeter.get();
        } finally {
            ResourceContext.unbindThreadContext();
        }
    }
 

Example using a NotifyingMeter with callback to count bytes


    public void test1() {
        ResourceContextFactory rfactory = ResourceContextFactory.getInstance();
        ResourceContext rcontext = rfactory.create("test");

        SimpleMeter fileOpenMeter = SimpleMeter.create(ResourceType.FILE_OPEN);
        rcontext.addResourceMeter(fileOpenMeter);

        SimpleMeter fileWriteMeter = SimpleMeter.create(ResourceType.FILE_WRITE);
        rcontext.addResourceMeter(fileWriteMeter);

        SimpleMeter threadCPUMeter = SimpleMeter.create(ResourceType.THREAD_CPU);
        rcontext.addResourceMeter(threadCPUMeter);

        SimpleMeter heapAllocMeter = SimpleMeter.create(ResourceType.HEAP_ALLOCATED);
        rcontext.addResourceMeter(heapAllocMeter);

        AtomicLong progress = new AtomicLong();
        NotifyingMeter fileReadMeter = NotifyingMeter.create(ResourceType.FILE_READ,
                (ResourceMeter c, long prev, long amt, ResourceId id) -> {
                    // total up the lengths of the positive requests
                    progress.getAndAdd(Math.max(0, amt));
                    return amt;
                });
        rcontext.addResourceMeter(fileReadMeter);

        rcontext.bindThreadContext();
        try {
            FileConsumer fc = FileConsumer.create();
            fc.write();
            fc.read();
        } catch (IOException ioe) {
            System.out.printf("ioe: %s%n", ioe);
        } finally {
            ResourceContext.unbindThreadContext();
        }
        System.out.printf(" cpu:        %9d ns%n", threadCPUMeter.getValue());
        System.out.printf(" file open:  %9d bytes%n", fileOpenMeter.getValue());
        System.out.printf(" file read:  %9d bytes%n", fileReadMeter.getValue());
        System.out.printf(" file write: %9d bytes%n", fileWriteMeter.getValue());
        System.out.printf(" heap total: %9d bytes%n", heapAllocMeter.getValue());
        System.out.printf(" progress:   %9d bytes%n", progress.get());
    }
 
Produces the output

 cpu:         76960825 ns
 file open:          8 bytes
 file read:      82639 bytes
 file write:     82639 bytes
 heap total:    801624 bytes
 progress:       99188 bytes
 
 
Implementation Requirements:
Unless otherwise specified, passing null as an argument to a constructor or method will cause a NullPointerException to be thrown.
Since:
8u40
Commercial feature
This is a commercial feature that must be unlocked before being used. To learn more about commercial features and how to unlock them visit http://www.oracle.com/technetwork/java/javaseproducts/.