In MAT I have Retained Heap with 0 Shallow Heap (?!?) - memory-leaks

I'm analyzing a heap dump with Eclipse Memory Analyzer (MAT).
I have a line in Heap Histogram, where Objects and Shallow Heap are 0 but there is a big amount of Retained Heap.
What does it mean? Is it not assigned to an object instance but it's only a static content? Or is it a bug in MAT?

AuthPolicy is an abstract class. As a result, there are no instances of that class. However, AuthPolicy does have some static fields source code of AuthPolicy. It does have a HashMap and ArrayList, The retained space is probably stuck in there:
...
public abstract class AuthPolicy {
private static final HashMap SCHEMES = new HashMap();
private static final ArrayList SCHEME_LIST = new ArrayList();
...

Related

DI containers leak memory or BenchmarksDotNet MemoryDiagnoser delivers inaccurate measurements?

Introduction
We are trying to catch potential memory leaks using BenchmarksDotNet.
For the simplicity of example, here is an unsophisticated TestClass:
public class TestClass
{
private readonly string _eventName;
public TestClass(string eventName)
{
_eventName = eventName;
}
public void TestMethod() =>
Console.Write($#"{_eventName} ");
}
We are implementing benchmarking though NUnit tests in netcoreapp2.0:
[TestFixture]
[MemoryDiagnoser]
public class TestBenchmarks
{
[Test]
public void RunTestBenchmarks() =>
BenchmarkRunner.Run<TestBenchmarks>(new BenchmarksConfig());
[Benchmark]
public void TestBenchmark1() =>
CreateTestClass("Test");
private void CreateTestClass(string eventName)
{
var testClass = new TestClass(eventName);
testClass.TestMethod();
}
}
The test output contains following summary:
Method | Mean | Error | Allocated |
--------------- |-----:|------:|----------:|
TestBenchmark1 | NA | NA | 0 B |
The test output also contains all the Console.Write output which proves that 0 B here means no memory was leaked rather than no code was run because of compiler optimization.
Problem
The confusion begins when we attempt to resolve TestClass with TinyIoC container:
[TestFixture]
[MemoryDiagnoser]
public class TestBenchmarks
{
private TinyIoCContainer _container;
[GlobalSetup]
public void SetUp() =>
_container = TinyIoCContainer.Current;
[Test]
public void RunTestBenchmarks() =>
BenchmarkRunner.Run<TestBenchmarks>(new BenchmarksConfig());
[Benchmark]
public void TestBenchmark1() =>
ResolveTestClass("Test");
private void ResolveTestClass(string eventName)
{
var testClass = _container.Resolve<TestClass>(
NamedParameterOverloads.FromIDictionary(
new Dictionary<string, object> {["eventName"] = eventName}));
testClass.TestMethod();
}
}
The summary indicates 1.07 KB was leaked.
Method | Mean | Error | Allocated |
--------------- |-----:|------:|----------:|
TestBenchmark1 | NA | NA | 1.07 KB |
Allocated value increases proportionally to the number of ResolveTestClass calls from TestBenchmark1, the summary for
[Benchmark]
public void TestBenchmark1()
{
ResolveTestClass("Test");
ResolveTestClass("Test");
}
is
Method | Mean | Error | Allocated |
--------------- |-----:|------:|----------:|
TestBenchmark1 | NA | NA | 2.14 KB |
This indicates that either TinyIoC is keeping the reference to each resolved object (which does not seem to be true according to source code) or BenchmarksDotNet measurements include some additional memory allocations outside of method marked with [Benchmark] attribute.
The config used in both cases:
public class BenchmarksConfig : ManualConfig
{
public BenchmarksConfig()
{
Add(JitOptimizationsValidator.DontFailOnError);
Add(DefaultConfig.Instance.GetLoggers().ToArray());
Add(DefaultConfig.Instance.GetColumnProviders().ToArray());
Add(Job.Default
.WithLaunchCount(1)
.WithTargetCount(1)
.WithWarmupCount(1)
.WithInvocationCount(16));
Add(MemoryDiagnoser.Default);
}
}
By the way, replacing TinyIoC with Autofac dependency injection framework didn't change the situation much.
Questions
Does it mean all DI framework have to implement some sort of cache for resolved objects? Does it mean BenchmarksDotNet is used in wrong way in a given example? Is it a good idea to hunt for memory leaks with the combination of NUnit and BenchmarksDotNet in the first place?
I am the person who implemented MemoryDiagnoser for BenchmarkDotNet and I am very happy to answer this question.
But first I am going to describe how the MemoryDiagnoser works.
It gets the number of allocated memory by using available API.
It performs one extra iteration of benchmark runs. In your case, it's 16 (.WithInvocationCount(16))
It gets the number of allocated memory by using available API.
final result = (totalMemoryAfter - totalMemoryBefore) / invocationCount
How accurate is the result? It is as accurate as the available APIs that we are using: GC.GetAllocatedBytesForCurrentThread() for .NET Core 1.1+ and AppDomain.MonitoringTotalAllocatedMemorySize for .NET 4.6+.
The thing called GC Allocation Quantum defines the size of allocated memory. It is usually 8k bytes.
What does it really mean: if we allocate a single object with new object() and GC needs to allocate memory for it (the current segment is full) it's going to allocate 8k of memory. And both APIs are going to report 8k memory allocated after a single object allocation.
Console.WriteLine(AppDomain.MonitoringTotalAllocatedMemorySize);
GC.KeepAlive(new object());
Console.WriteLine(AppDomain.MonitoringTotalAllocatedMemorySize);
might end up in reporting:
x
x + 8000
How BenchmarkDotNet deals with this problem? We perform a LOT of invocations (usually millions or billions), so minimize the allocation quantum size problem (it's never 8k for us).
How to fix the problem in your case: set the WithInvocationCount to a bigger number (maybe 1000).
To verify the results you might consider using some Memory Profiler. Personally I used Visual Studio Memory Profiler which is part of Visual Studio.
Another alternative is to use JetBrains.DotMemoryUnit. It's most probably the best tool in your case.

Show a non-concurrent Map breaking under multiple threads

I'm trying to demonstrate the problem of using an ordinary Map with multiple concurrent tasks. The following example (which compiles and runs) is intended to show the Map failing:
import java.util.*;
import java.util.stream.*;
import java.util.concurrent.*;
class BreakMap2 implements Runnable {
private Map<Integer, Integer> map;
public BreakMap2(Map<Integer, Integer> map) {
this.map = map;
}
#Override
public void run() {
while(true) {
int key = ThreadLocalRandom.current().nextInt(10_000);
if(map.containsKey(key)) {
assert map.get(key) == key;
}
map.put(key, key);
}
}
}
public class MapBreaker2 {
public static void main(String[] args) {
Map<Integer, Integer> map = new HashMap<>();
IntStream.range(0, 1000)
.mapToObj(i -> new BreakMap2(map))
.map(CompletableFuture::runAsync)
.collect(Collectors.toList())
.forEach(CompletableFuture::join);
}
}
This doesn't demonstrate the problem (it doesn't fail). How can I do this more effectively? Is there an approach that will fail quickly and reliably?
To clarify, I'm trying to show how it's unsafe to have multiple tasks writing to a Map that is not designed for concurrent use. I'm trying to create something that will show an incorrect write to a Map because of concurrent access.
Edit: I've simplified the example so now it just runs forever until you hit Control-C. What I'd like instead is for a failure to stop the program.
It’s not clear which kind of “incorrect write” you are trying to provoke.
There is a broad variety of problems that can occur with concurrent updates of a data structure. One infamous problem with unsynchronized concurrent updates of HashMap, which indeed shows up in real applications, is HashMap.get being stuck in an infinite loop but, of course, your program which runs infinitely anyway wouldn’t be able to spot that.
The only thing you are testing is the value of a stored Integer with assert map.get(key) == key; This doesn’t test the object identity (otherwise it was doomed to fail due to the unspecified object identity of auto-boxed values), but rather the contained int value, which benefits from guarantees made for final fields, even if their owner object is published via a data race. So you are unable to see an uninitialized value here and it’s hard to imagine any scenario in which you could encounter a wrong value.
Since you are storing immutable objects whose values are immune to data races, only the structural updates to the Map itself may have an effect. But these are rare. You are filling the Map with random keys between 0 and 10000 in an infinite loop, so once all ten thousand distinct keys in that range are encountered, there will be no structural change anymore. Chances are good, that the first asynchronous task will reach that state even before the next task starts its work. Even if there is a short overlapping phase, the likelihood of encountering a data race right in that time window is low.
After that short time window, you are only replacing the values of existing mappings, as said, with objects immune to data races and, since they represent the same boxed values, the JVM may even optimize away the entire update.
If you want a program with a higher likelihood of failing, you may try the following. It performs a simple naive transfer from one Map to another, probing an entry and putting it into the target map if it exists. It looks simple and will indeed run smoothly with a thread count of one, but will fail badly in most environments when using any other thread count.
public class MapBreaker2 {
public static void main(String[] args) throws InterruptedException {
int threadCount = 2; // try varying that number
Map<Integer, Integer> source = IntStream.range(0, 10_000)
.boxed().collect(Collectors.toMap(i->i, i->i));
System.out.println("trying to copy "+source.size()+" mappings without synchonizing");
Map<Integer, Integer> target = new HashMap<>();
Callable<?> job=() -> {
while(!source.isEmpty()) {
int key = ThreadLocalRandom.current().nextInt(10_000);
Integer value=source.remove(key);
if(value!=null)
target.put(key, value);
}
return null;
};
ExecutorService pool = Executors.newCachedThreadPool();
pool.invokeAll(Collections.nCopies(threadCount, job));
pool.shutdown();
System.out.println(target.size());
assert source.isEmpty();
assert target.size()==10_000;
}
}
But it should be emphasized that multi-threading without synchronization still is unpredictable, so it may run without a noticeable error in one or another test run…

Groovy's #CompileStatic and map constructors

I'm using #CompileStatic for the first time, and confused as to how Groovy's map constructors work in this situation.
#CompileStatic
class SomeClass {
Long id
String name
public static void main(String[] args) {
Map map = new HashMap()
map.put("id", 123L)
map.put("name", "test file")
SomeClass someClass1 = new SomeClass(map) // Does not work
SomeClass someClass2 = map as SomeClass // Works
}
}
Given the code above I see the following error when trying to compile
Groovyc: Target constructor for constructor call expression hasn't been set
If #CompileStatic is removed, both constructors work properly.
Can anyone explain why new SomeClass(map) does not compile with #CompileStatic? And a possible addition, why does map as SomeClass still work?
Groovy actually does not give you a "Map-Constructor". The constructors
in your class are what you write down. If there are none (like in your case),
then there is the default c'tor.
But what happens, if you use the so called map c'tor (or rather call it
"object construction by map")? The general approach of groovy is like this:
create a new object using the default c'tor (this is the reason, why the
construction-by-map no longer works, if there would be just e.g.
SomeClass(Long id, String name))
then use the passed down map and apply all values to the properties.
If you disassmble your code (with #CompileDynamic (the default)) you see, that
the construction is handled by CallSite.callConstructor(Object,Object),
which boils down to this this code area.
Now bring in the version of this construction by map, that is more familiar
for the regular groovyist:
SomeClass someClass3 = new SomeClass(id: 42L, name: "Douglas").
With the dynamic version of the code, the disassembly of this looks actually
alot like your code with the map. Groovy creates a map from the param(s) and
sends it off to callConstructor - so this is actually the same code path
taken (minus the implicit map creation).
For now ignore the "cast-case", as it is actually the same for both static and
dynamic: it will be sent to ScriptBytecodeAdapter.asType which basically
gives you the dynamic behaviour in any case.
Now the #CompileStatic case: As you have witnessed, your call with an
explicit map for the c'tor no longer works. This is due to the fact, that
there never was an explicit "map-c'tor" in the first place. The class still
only has its default c'tor and with static compilation groovyc now can just
work with the things that are there (or not if there aren't in this case).
What about new SomeClass(id: 42L, name: "Douglas") then? This still works
with static compilation! The reason for this is, that groovyc unrolls this
for you. As you can see, this simply boils down to def o = new SomeClass();
o.setId(42); o.setName('Douglas'):
new #2 // class SomeClass
dup
invokespecial #53 // Method "<init>":()V
astore_2
ldc2_w #54 // long 42l
dup2
lstore_3
aload_2
lload_3
invokestatic #45 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
invokevirtual #59 // Method setId:(Ljava/lang/Long;)V
aconst_null
pop
pop2
ldc #61 // String Douglas
dup
astore 5
aload_2
aload 5
invokevirtual #65 // Method setName:(Ljava/lang/String;)V
As the CompileStatic documentation says:
will actually make sure that the methods which are inferred as being
called will effectively be called at runtime. This annotation turns
the Groovy compiler into a static compiler, where all method calls are
resolved at compile time and the generated bytecode makes sure that
this happens
As a result, a constructor with a Map argument is searched in the static compilation to "resolve it at compile time", but it is not found and thereby there is a compilation error:
Target constructor for constructor call expression hasn't been set
Adding such a constructor solves the issue with the #CompileStatic annotation, since it is resolved at compile time:
import groovy.transform.CompileStatic
#CompileStatic
class SomeClass {
Long id
String name
SomeClass(Map m) {
id = m.id as Long
name = m.name as String
}
public static void main(String[] args) {
Map map = new HashMap()
map.put("id", 123L)
map.put("name", "test file")
SomeClass someClass1 = new SomeClass(map) // Now it works also
SomeClass someClass2 = map as SomeClass // Works
}
}
You can check StaticCompilationVisitor if you want to dig deeper.
Regarding the line
SomeClass someClass2 = map as SomeClass
You are using there the asType() method of Groovy's GDK java.util.Map, so it is therefore solved at runtime even in static compilation:
Coerces this map to the given type, using the map's keys as the public
method names, and values as the implementation. Typically the value
would be a closure which behaves like the method implementation.

Constants in Haxe

How do you create public constants in Haxe? I just need the analog of good old const in AS3:
public class Hello
{
public static const HEY:String = "hey";
}
The usual way to declare a constant in Haxe is using the static and inline modifiers.
class Main {
public static inline var Constant = 1;
static function main() {
trace(Constant);
trace(Test.Constant);
}
}
If you have a group of related constants, it can often make sense to use an enum abstract. Values of enum abstracts are static and inline implicitly.
Note that only the basic types (Int, Float, Bool) as well as String are allowed to be inline, for others it will fail with this error:
Inline variable initialization must be a constant value
Luckily, Haxe 4 has introduced a final keyword which can be useful for such cases:
public static final Regex = ~/regex/;
However, final only prevents reassignment, it doesn't make the type immutable. So it would still be possible to add or remove values from something like static final Values = [1, 2, 3];.
For the specific case of arrays, Haxe 4 introduces haxe.ds.ReadOnlyArray which allows for "constant" lists (assuming you don't work around it using casts or reflection):
public static final Values:haxe.ds.ReadOnlyArray<Int> = [1, 2, 3];
Values = []; // Cannot access field or identifier Values for writing
Values.push(0); // haxe.ds.ReadOnlyArray<Int> has no field push
Even though this is an array-specific solution, the same approach can be applied to other types as well. ReadOnlyArray<T> is simply an abstract type that creates a read-only "view" by doing the following:
it wraps Array<T>
it uses #:forward to only expose fields that don't mutate the array, such as length and map()
it allows implicit casts from Array<T>
You can see how it's implemented here.
For non-static variables and objects, you can give them shallow constness as shown below:
public var MAX_COUNT(default, never):Int = 100;
This means you can read the value in the 'default' way but can 'never' write to it.
More info can be found http://adireddy.github.io/haxe/keywords/never-inline-keywords.

MFC multithreading with delete[] , dbgheap.c

I've got a strange problem and really don't understand what's going on.
I made my application multi-threaded using the MFC multithreadclasses.
Everything works well so far, but now:
Somewhere in the beginning of the code I create the threads:
m_bucketCreator = new BucketCreator(128,128,32);
CEvent* updateEvent = new CEvent(FALSE, FALSE);
CWinThread** threads = new CWinThread*[numThreads];
for(int i=0; i<8; i++){
threads[i]=AfxBeginThread(&MyClass::threadfunction, updateEvent);
m_activeRenderThreads++;
}
this creates 8 threads working on this function:
UINT MyClass::threadfunction( LPVOID params ) //executed in new Thread
{
Bucket* bucket=m_bucketCreator.getNextBucket();
...do something with bucket...
delete bucket;
}
m_bucketCreator is a static member. Now I get some thread error in the deconstructor of Bucket on the attempt to delete a buffer (however, the way I understand it this buffer should be in the memory of this thread, so I don't get why there is an error). On the attempt of delete[] buffer, the error happens in _CrtIsValidHeapPointer() in dbgheap.c.
Visual studio outputs the message that it trapped a halting point and this can be either due to heap corruption or because the user pressed f12 (I didn't ;) )
class BucketCreator {
public:
BucketCreator();
~BucketCreator(void);
void init(int resX, int resY, int bucketSize);
Bucket* getNextBucket(){
Bucket* bucket=NULL;
//enter critical section
CSingleLock singleLock(&m_criticalSection);
singleLock.Lock();
int height = min(m_resolutionY-m_nextY,m_bucketSize);
int width = min(m_resolutionX-m_nextX,m_bucketSize);
bucket = new Bucket(width, height);
//leave critical section
singleLock.Unlock();
return bucket;
}
private:
int m_resolutionX;
int m_resolutionY;
int m_bucketSize;
int m_nextX;
int m_nextY;
//multithreading:
CCriticalSection m_criticalSection;
};
and class Bucket:
class Bucket : public CObject{
DECLARE_DYNAMIC(RenderBucket)
public:
Bucket(int a_resX, int a_resY){
resX = a_resX;
resY = a_resY;
buffer = new float[3 * resX * resY];
int buffersize = 3*resX * resY;
for (int i=0; i<buffersize; i++){
buffer[i] = 0;
}
}
~Bucket(void){
delete[] buffer;
buffer=NULL;
}
int getResX(){return resX;}
int getResY(){return resY;}
float* getBuffer(){return buffer;}
private:
int resX;
int resY;
float* buffer;
Bucket& operator = (const Bucket& other) { /*..*/}
Bucket(const Bucket& other) {/*..*/}
};
Can anyone tell me what could be the problem here?
edit: this is the other static function I'm calling from the threads. Is this safe to do?
static std::vector<Vector3> generate_poisson(double width, double height, double min_dist, int k, std::vector<std::vector<Vector3> > existingPoints)
{
CSingleLock singleLock(&m_criticalSection);
singleLock.Lock();
std::vector<Vector3> samplePoints = std::vector<Vector3>();
...fill the vector...
singleLock.Unlock();
return samplePoints;
}
All the previous replies are sound. For the copy constructor, make sure that it doesn't just copy the buffer pointer, otherwise that will cause the problem. It needs to allocate a new buffer, not the pointer value, which would cause an error in 'delete'. But I don't get the impression that the copy contructor will get called in your code.
I've looked at the code and I am not seeing any error in it as is. Note that the thread synchronization isn't even necessary in this GetNextBucket code, since it's returning a local variable and those are pre-thread.
Errors in ValidateHeapPointer occur because something has corrupted the heap, which happens when a pointer writes past a block of memory. Often it's a for() loop that goes too far, a buffer that wasn't allocated large enough, etc.
The error is reported during a call to 'delete' because that's when the heap is validated for bugs in debug mode. However, the error has occurred before that time, it just happens that the heap is checked only in 'new' and 'delete'. Also, it isn't necessarily related to the 'Bucket' class.
What you need to need to find this bug, short of using tools like BoundsChecker or HeapValidator, is comment out sections of your code until it goes away, and then you'll find the offending code.
There is another method to narrow down the problem. In debug mode, include in your code, and sprinkle calls to _CrtCheckMemory() at various points of interest. That will generate the error when the heap is corrupted. Simply move the calls in your code to narrow down at what point the corruption begins to occur.
I don't know which version of Visual C++ you are using. If you're using a earlier one like VC++ 6.0, make sure that you are using the Multitreaded DLL version of the C Run Time Library in the compiler option.
You're constructing a RenderBucket. Are you sure you're calling the 'Bucket' class's constructor from there? It should look like this:
class RenderBucket : public Bucket {
RenderBucket( int a_resX, int a_resY )
: Bucket( a_resX, a_resY )
{
}
}
Initializers in the Bucket class to set the buffer to NULL is a good idea... Also making the Default constructor and copy constructor private will help to make double sure those aren't being used. Remember.. the compiler will create these automatically if you don't:
Bucket(); <-- default constructor
Bucket( int a_resx = 0, int a_resy = 0 ) <-- Another way to make your default constructor
Bucket(const class Bucket &B) <-- copy constructor
You haven't made a private copy constructor, or any default constructor. If class Bucket is constructed via one of these implicitly-defined methods, buffer will either be uninitialized, or it will be a copied pointer made by a copy constructor.
The copy constructor for class Bucket is Bucket(const Bucket &B) -- if you do not explicitly declare a copy constructor, the compiler will generate a "naive" copy constructor for you.
In particular, if this object is assigned, returned, or otherwise copied, the copy constructor will copy the pointer to a new object. Eventually, both objects' destructors will attempt to delete[] the same pointer and the second attempt will be a double deletion, a type of heap corruption.
I recommend you make class Bucket's copy constructor private, which will cause attempted copy construction to generate a compile error. As an alternative, you could implement a copy constructor which allocates new space for the copied buffer.
Exactly the same applies to the assignment operator, operator=.
The need for a copy constructor is one of the 55 tips in Scott Meyer's excellent book, Effective C++: 55 Specific Ways to Improve Your Programs and Designs:
This book should be required reading for all C++ programmers.
If you add:
class Bucket {
/* Existing code as-is ... */
private:
Bucket() { buffer = NULL; } // No default construction
Bucket(const Bucket &B) { ; } // No copy construction
Bucket& operator= (const Bucket &B) {;} // No assignment
}
and re-compile, you are likely to find your problem.
There is also another possibility: If your code contains other uses of new and delete, then it is possible these other uses of allocated memory are corrupting the linked-list structure which defines the heap memory. It is common to detect this corruption during a call to delete, because delete must utilize these data structures.

Resources