serkan-ozal / mysafe

My Unsafe - Unsafe Interceptor, Native Memory Leak Tracker and Access Checker on the JVM
Apache License 2.0
41 stars 4 forks source link

MySafe

My Unsafe - Unsafe Interceptor, Native Memory Leak Tracker and Access Checker on the JVM

1. What is MySafe?

MySafe is a framework (based on Jillegal-Agent) for managing memory accesses over sun.misc.Unsafe. MySafe intercepts (instruments) sun.misc.Unsafe calls and keeps records of allocated memories. So it can give the allocated memory informations and detect the invalid memory accesses.

2. Installation

In your pom.xml, you must add repository and dependency for MySafe. You can change mysafe.version to any existing MySafe library version. Latest version of MySafe is 2.1.

...
<properties>
    ...
    <mysafe.version>2.1</mysafe.version>
    ...
</properties>
...
<dependencies>
    ...
    <dependency>
        <groupId>tr.com.serkanozal</groupId>
        <artifactId>mysafe</artifactId>
        <version>${mysafe.version}</version>
    </dependency>
    ...
</dependencies>
...
<repositories>
    ...
    <repository>
        <id>serkanozal-maven-repository</id>
        <url>https://github.com/serkan-ozal/maven-repository/raw/master/</url>
    </repository>
    ...
</repositories>
...

3. Configurations

4. Usage

There are 3 ways of activating MySafe:

4.1. Java Agent Based Usage by VM Argument

MySafe can be activated through Java agent (Jillegal-Agent) by using sun.misc.Unsafe instrumenter of MySafe via -javaagent:<path_to_jillegal_agent>\<jillegal_agent_jar>="-p tr.com.serkanozal.mysafe.impl.processor.MySafeProcessor".

For example: -javaagent:$M2_HOME\tr\com\serkanozal\jillegal-agent\2.0\jillegal-agent-2.0.jar="-p tr.com.serkanozal.mysafe.impl.processor.MySafeProcessor"

4.2. Java Agent Based Usage Programmatically

MySafe can be activated programmatically by MySafe.youAreMine();.

4.3. ClassLoader Based Usage by VM Argument

MySafe can be activated also by defining its classloader as system classloader via -Djava.system.class.loader=tr.com.serkanozal.mysafe.impl.classloader.MySafeClassLoader.

5. API

5.1. AllocatedMemoryStorage

AllocatedMemoryStorage interface is contract point to store allocated memories. It is specified via mysafe.allocatedMemoryStorageImpl system property.

5.2. IllegalMemoryAccessListener

IllegalMemoryAccessListener interface is contract point to be notified when illegal memory access occurred. It is specified via mysafe.illegalMemoryAccessListenerImpl system property.

5.3. AllocatedMemoryIterator

AllocatedMemoryIterator interface is contract point for iterating allocated memories.

Here is its sample usage:

// Iterate on all allocated memories and print them
MySafe.iterateOnAllocatedMemories(new AllocatedMemoryIterator() {

  @Override
  public void onAllocatedMemory(long address, long size) {
    System.out.println("onAllocatedMemory >>> " + 
                          "address=" + address + 
                          ", size=" + size);
  }

});

5.4. MemoryListener

MemoryListener interface is contract point to be notified for memory usage (allocation/free/reallocation).

Here is its sample usage:

// Create listener to be notified for each allocate/free/reallocate
MemoryListener listener = new MemoryListener() {

  @Override
  public void beforeAllocateMemory(long size) {
    System.out.println("beforeAllocateMemory >>> " + 
                          "size=" + size);
  }

  @Override
  public void afterAllocateMemory(long address, long size) {
    System.out.println("afterAllocateMemory >>> " + 
                          "address=" + address + 
                          ", size=" + size);
  }

  @Override
  public void beforeFreeMemory(long address) {
    System.out.println("beforeFreeMemory >>> " + 
                          "address=" + address);
  }

  @Override
  public void afterFreeMemory(long address, long size, boolean isKnownAddress) {
    System.out.println("afterFreeMemory >>> " + 
                          "address=" + address + 
                          ", size=" + size + 
                          ", isKnownAddress=" + isKnownAddress);
  }

  @Override
  public void beforeReallocateMemory(long oldAddress, long oldSize) {
    System.out.println("beforeReallocateMemory >>> " + 
                          "oldAddress=" + oldAddress + 
                          ", oldSize=" + oldSize);
  }

  @Override
  public void afterReallocateMemory(long oldAddress, long oldSize, 
                                    long newAddress, long newSize, boolean isKnownAddress) {
    System.out.println("afterReallocateMemory >>> " + 
                          "oldAddress=" + oldAddress + 
                          ", oldSize=" + oldSize +
                          ", newAddress=" + newAddress + 
                          ", newSize=" + newSize +
                          ", isKnownAddress=" + isKnownAddress);
  }

};

...

// Register listener to be notified for each allocate/free
MySafe.registerMemoryListener(listener);

...

// Deregister registered listener
MySafe.deregisterMemoryListener(listener);

5.5. Dumping Allocated Native Memories

All allocated memories can be dumped via MySafe.dumpAllocatedMemories() or MySafe.dumpAllocatedMemories(PrintStream) methods.

Here is its sample usage:

// Dump all allocated memories to console
MySafe.dumpAllocatedMemories();

...

PrintStream myPrintStream = ...
// Dump all allocated memories to `myPrintStream`
MySafe.dumpAllocatedMemories(myPrintStream);

5.6. AllocationPathManager

AllocationPathManager interface is contract point to manage allocation path & address mappings/un-mappings and allocation path provide related operations. It is specified via mysafe.allocationPathManagerImpl system property.

5.7. Dumping Allocation Paths

All unique allocation paths with allocated memories through them can be dumped via MySafe.dumpAllocationPaths() or MySafe.dumpAllocationPaths(PrintStream) methods if allocation path monitoring is enabled by mysafe.enableAllocationPathMonitoringMode property.

Here is its sample usage:

// Dump all allocation paths with allocated memories through them to console
MySafe.dumpAllocationPaths();

...

PrintStream myPrintStream = ...
// Dump all allocation paths with allocated memories through them to `myPrintStream`
MySafe.dumpAllocationPaths(myPrintStream);

5.8. Generating Allocation Path Diagram

All unique allocation paths with allocated memories through them can be dumped via MySafe.generateAllocationPathDiagrams() method if allocation path monitoring is enabled by mysafe.enableAllocationPathMonitoringMode property.

Here is its sample usage:

// Generate allocation path diagram
MySafe.generateAllocationPathDiagrams();

6. Demo

Here is demo application for demonstrating how to iterate on allocated memories and dump them.

Here is demo application for demonstrating how to track memory allocation, reallocation and free operations.

Here is demo application for demonstrating how to be notified on illegal memory accesses.

Here is demo application for demonstrating how to integrate MySafe with custom memory managers.

Here is demo application for demonstrating how to hunt native memory leaks via MySafe.

Here is the generated allocation path diagram for the NativeMemoryLeakHuntingDemo which shows the cause of native memory leak: native-memory-leak-hunting

7. Fixes & Enhancements

Bug fixes and enhancements at each release:

7.1. Version 1.1

7.2. Version 2.0

7.3. Version 2.1

8. Roadmap