Sunday, November 23, 2014

G1 GC: Humongous Objects and Humongous Allocations

For Garbage First Garbage Collector (G1 GC), any object that is more than half a region size is considered a Humongous Object.   A humongous object is directly allocated into Humongous Regions.[1]

In this article, we will discuss the following topics:
  • Humongous regions and humongous allocations
  • How humongous allocations impact G1's performance?
  • How to detect humongous allocations?
    • Basic Investigation
    • Advanced Investigation

Humongous Regions and Humongous Allocations


A humongous object is allocated directly in the humongous regions. These humongous regions are a contiguous set of regions. StartsHumongous marks the start of the contiguous set and ContinuesHumongous marks the continuation of the set.

Before allocating any humongous region, the marking threshold is checked, initiating a concurrent cycle, if necessary. Dead humongous objects are freed at the end of the marking cycle during the cleanup phase also during a full garbage collection cycle (but, a new implementation has changed this; see the next section).

Since each individual set of StartsHumongous and ContinuesHumongous regions contains just one humongous object, the space between the end of the humongous object and the end of the last region spanned by the object is unused. For objects that are just slightly larger than a multiple of the heap region size, this unused space can cause the heap to become fragmented.

How Humongous Allocations Impact G1's Performance?


In the old implementation, humongous objects are not released until after a full concurrent marking cycle.[4]  This is far from ideal for many transaction-based enterprise applications that create short-lived (i.e., in the transaction scope) humongous objects such as ResultSet(s) generated from JDBC queries.  This results in the heap filling up relatively quickly and leads to unnecessary marking cycles to reclaim them.

A new implementation since:
java version "1.8.0_40-ea"
Java(TM) SE Runtime Environment (build 1.8.0_40-ea-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b05, mixed mode)
handles humongous regions differently and can reclaim them earlier if they are short-lived (see [4] for details).

For investigating humongous allocations in G1, you should begin with the following minimal set of VM options:
  • -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintReferenceGC (-XX:+UseG1GC)

Basic Humongous Allocation Investigation


For basic humongous allocations investigation, you simply add a new option:
  • -XX:+PrintAdaptiveSizePolicy
This option will print out something like below:
12025.832: [G1Ergonomics (Concurrent Cycles) request concurrent cycle initiation, reason: occupancy higher than threshold, occupancy: 3660578816 bytes, allocation request: 1048592 bytes, threshold: 3650722120 bytes (85.00 %), source: concurrent humongous allocation]
From the above, we saw a humongous allocation is initiated with a request size of 1048592 bytes. Note that our region size is 1MBytes in this test. So, the request object is considered as humongous (i.e., 1048592 Bytes > half of 1 MBytes).

In the output, you can also find the following entries:
      [Humongous Reclaim: 0.0 ms]
         [Humongous Total: 54]
         [Humongous Candidate: 0]
         [Humongous Reclaimed: 0]
This shows that there are 54 humongous regions found in this GC event.   Also, none of them were reclaimed in this GC event. The reason is that the current algorithm is relatively conservative and it skips humongous objects for reclamation if there are sparse references into them.  In the case that those references belongs to sparse table entries, G1 may improve the reclamation rate by discovering if they are actually not referenced at all after iterating the table.  A performance enhancement is pending for this effort now.[5]

Advanced Humongous Allocation Investigation


To further investigate humongous allocation in more details, you can add:
-XX:+PrintAdaptiveSizePolicy -XX:+UnlockExperimentalVMOptions -XX:+G1ReclaimDeadHumongousObjectsAtYoungGC -XX:G1LogLevel=finest -XX:+G1TraceReclaimDeadHumongousObjectsAtYoungGC
Note that the following VM options are experimental:
  • G1TraceReclaimDeadHumongousObjectsAtYoungGC[4]
  • G1ReclaimDeadHumongousObjectsAtYoungGC[3]
  • G1LogLevel (i.e., [fine|finer|finest])
So, that's why we added the unlock option;
-XX:+UnlockExperimentalVMOptions
With extra printing options, you will find detailed description of humongous allocations as shown below:
3708.669: [SoftReference, 0 refs, 0.0000340 secs]3708.669: [WeakReference, 1023 refs, 0.0001790 secs]3708.669: [FinalReference, 295 refs, 0.0007020 secs]3708.670: [PhantomReference, 0 refs, 0.0000060 secs]3708.670: [JNI Weak Reference, 0.0000140 secs]Live humongous 1 region 9 size 65538 with remset 1 code roots 0 is marked 0 live-other 0 obj array 0

Live humongous 1 region 10 size 88066 with remset 1 code roots 0 is marked 0 live-other 0 obj array 0
Live humongous 1 region 15 size 262146 with remset 1 code roots 0 is marked 0 live-other 0 obj array 1
...
Finally, you can also use Java Flight Recorder (JFR) and Java Mission Control (JMC) to get information about humongous objects by showing their allocation sources with stack traces.[7]

References

  1. Garbage First Garbage Collector Tuning
  2. G1GC: Migration to, Expectations and Advanced Tuning
  3. Thread local allocation buffers (TLAB's)
  4. Early reclamation of large objects in G1
    • Introduced since 8u40 b02 and 8u45
    • Was not back ported to 8u20
  5. Early reclaim of large objects that are referenced by a few objects
  6. G1TraceReclaimDeadHumongousObjectsAtYoungGC
    • JDK-8058801
      • Prints information about live and dead humongous objects
        • (Before bug fix) prints that information when there is at least one humongous candidate.
        • (After bug fix) prints that information even when there is no humongous candidates; it also prints humongous object size in the output
  7. Java Mission Control (JMC) and Java Flight Recorder (JFR)

Saturday, November 22, 2014

Java SecurityManager: "java.security" and "java.policy" Files

In many cases, where the threat model does not include malicious code being run in the JVM, the Java Security Manager[1] is unnecessary. However, when untrusted third-parties use WebLogic Server[2] and untrusted classes are being run, the Java Security Manager may be useful.

In this article, we will discuss the following topics:
  1. What is Java Security Manager?
  2. What is "java.security" file?
  3. What is "java.policy" file?

Java Security Manager


The JVM has security mechanisms built into it that allow you to define restrictions to code through Java security policy files (i.e., java.policy file). The Java Security Manager uses these policies to enforce a set of permissions granted to classes. The permissions allow specified classes running in that instance of the JVM to allow or not allow certain runtime operations.

Therefore Java Security Manager can be used with WebLogic Server to provide additional protection for resources running in a Java Virtual Machine (JVM).[1] However, using a Java Security Manager is an optional security step.

To use the Java Security Manager with WebLogic Server, just specify:
-Djava.security.policy -Djava.security.manager
arguments when starting WebLogic Server. The -Djava.security.policy argument specifies a filename (using a relative or fully-qualified pathname) that contains Java 2 security policies.[5]

java.security


A security model can be as simple as the one supported in Linux or Windows file system—file permissions are granted to principals based on user IDs. Or it can be as sophisticated as the one implemented in Adobe Flash Player (see [6] for details). Java Security Manager supports a security model sits in between the two in terms of complexity and capability.

Sometimes a Java application (like, say, a Web browser) needs to run untrusted code within itself. In this case, Java system libraries need some way of distinguishing between calls originating in untrusted code and calls originating from the trusted application itself. Clearly, the calls originating in untrusted code need to be restricted to prevent hostile activities. By contrast, calls originating in the application itself should be allowed to proceed (as long as they follow any security rules that the operating system mandates).

Security is all about separation by creating protection domains. Access control in Java Security Manager is enforced with the help of:[10]
  • Executable Code Identity
    • Decisions are based on the identity of the executable code
      • AccessController in java.security package consults policy and uses stack inspection (see below) to decide whether to allow or disallow a call.
    • Executable code is categorized based on its URL of origin and the private keys used to sign the code:
      • Code source
        • Note that permission objects are associated with each code source
      • Signature
    • Trusted code vs untrusted code
  • Protected System Resource
    • File access
    • Network access (via sockets)
    • Listening ports, etc.
  • Permission (or privilege)
    • Permission is configure by:
      • Grant Target
        • Such as the name of a file
      • Grant Action
        • Such as "read" action on a file
    • Collection of Permissions
      • Homogeneous vs heterogeneous
  • Logical groupings
    • Separating groups from each other and granting groups particular permissions.

Stack Inspection

Java implements its security system by allowing security-checking code to examine the runtime stack for frames executing untrusted code. This is called stack inspection.[7] Java Security Manager inspects the stack in order to make access control decisions.

Each thread of execution has its own runtime stack. The stack grows and shrinks during typical program operation. Each stack frame includes both a method call and a trust label (T for trusted, U for untrusted).

Security Properties File Location

The security properties file is located in the file named

java.home/lib/security/java.security (Solaris/Linux/Mac OS X)
java.home\lib\security\java.security (Windows)

java.policy


Java security can be dictated by security policies. A policy file can be composed via a simple text editor, or via the graphical Policy Tool utility.[8] There is by default a single system-wide policy file, and a single (optional) user policy file. Policy can be set by the user (usually a bad idea) or by the system administrator, and is represented in the class java.security.Policy.

The configuration file(s) specify what permissions are allowed for code from a specified code source, and executed by a specified principal. Each configuration file must be encoded in UTF-8.[4]

Policy File Location

Policy file locations are specified in the security properties file (i.e., java.security).  For example, the default system and user policy files are defined using URL specification in the security properties file as:

policy.url.1=file:${java.home}/lib/security/java.policy
policy.url.2=file:${user.home}/.java.policy


System Policy File

The system policy file is meant to grant system-wide code permissions. It is by default located at

java.home/lib/security/java.policy (Solaris/Linux/Mac OS X) 
java.home\lib\security\java.policy (Windows)

The java.policy file installed with the JDK grants all permissions to standard extensions, allows anyone to listen on un-privileged ports, and allows any code to read certain "standard" properties that are not security-sensitive, such as the "os.name" and "file.separator" properties.

Executable code is categorized based on its URL of origin and the private keys used to sign the code. The security policy maps a set of access permissions to code characterized by particular origin/signature information. Protection domains can be created on demand and are tied to code with particular CodeBase and SignedBy properties.

Code can be signed with multiple keys and can potentially match multiple policy entries. In this case, permissions are granted in an additive fashion

References