I'm finding CG appears to have a memory leak. I submitted a report via nvidia.com, but if you try this here:
If you remove the line that says
cgD3D11SetTextureParameter( g.theTexture, g.sharedTex ) ;
The leak stops.
Does CG 3.0 really leak?
Using ATI Radeon 5850 GPU / Windows 7 64-bit.
Yes, it leaks. Internally it creates a ShaderResourceView on every call, and never releases it. I think the API is ill-designed, they should have taken a ShaderResourceView* as a parameter to this function, instead of just a Resource*.
I posted about this on nvidia forums about 6 months ago and never got a response
Is your report posted publicly? Or some kind of private support ticket?
Yes, Cg 3.0 leaks every time you call cgD3D11SetTextureParameter(), causing your application's memory usage to climb. Unfortunately it makes Cg 3.0 with D3D11 completely unusable. One symptom of this is that, after a while of your application running, it will stop rendering and the screen will just go black. I wasted a lot of time trying to determine the cause of this before discovering the Cg bug.
If anybody is wondering why this isn't apparent with the Cg D3D11 demos, its because the few that actually use textures are so simple that they can get away with only calling cgD3D11SetTextureParameter() once at the start.
This same bug remains with Cg Toolkit 3.1 (April 2012).
jmp [UPDATE] ;; skip obsolete text segment
Could it be that Cg is being destroyed after d3d so it doesn't release the reference on time? Or vice-versa? such as the function acquiring the texture but not releasing it before d3d closes, because when you set a texture to a shader, the texture is acquired until shader resources are released somehow. You are destroying the d3d context, here:
SAFE_RELEASE( g.d3d );
SAFE_RELEASE( g.gpu );
Later on, you free the shader, as follows CleanupCg():
cgDestroyProgram( g.v_vncShader );
checkForCgError( "destroying vertex program" );
cgDestroyProgram( g.px_vncShader );
checkForCgError( "destroying fragment program" );
Try to change the order of the calls in a way you first release all resources from both cg and d3d, this: cgD3D11SetDevice( g.cgContext, NULL ); should also be called before releasing the d3d context, just in case.
UPDATE:
This should be different inside WinMain():
initD3D11() ; // << FIRST you init D3D
initCg() ; // << SECOND you init CG with the D3D pointers
initD2D1() ; //
initVBs() ;
// Main message loop
while( WM_QUIT != msg.message ){ /* loop code */ }
CleanupDevice(); //// << FIRST you release all D3D, when Cg is still referencing it (why?).
CleanupCg(); //// << SECOND if something in the Cg runtime depend on d3dcontext which you just destroyed, it will crash or leak or do whatever it wants
so you should swap them to ensure Cg to free any d3d pointer:
CleanupCg(); //// << FIRST release Cg to ensure it's not referencing D3D anymore.
CleanupDevice(); //// << SECOND D3D isn't either referencing or being referenced by Cg, so just release it all
You could also provide the debugger output and other info as I asked down there, because you're basically saying "Cg seems to be broken, this is the whole code, look the line ###, is it broken?" but there are more than a thousand lines (1012) of C, C++ and shader code in your file, you basically provide no info but readily point to a Cg bug (based on... what?) which of course, if you're so sure, why would anyone look at the code if the code is fine? Which isn't by the way, not that I don't like it but... it got these little things such as the call ordering which are silly mistakes but that can make debugging a real hell, it's a clear bug, and I may also think that if I just looked into Main and found a bug, well there is a long way up to the render call and the Cg implementation, isn't it? I can't run the app on WinXP, but these errors are in the most predictable places :)
So... when your code is clean of any bug... ohh! look! what I've just found..
~VertexBuffer()
{
SAFE_RELEASE( vb );
SAFE_RELEASE( layout ) ;
}
turns out in VertexBuffer constructor you call iD3D->GetImmediateContext( &gpu ); and store the pointer in a private member, so... shouldn't you add:
SAFE_RELEASE( gpu ); // ? there are 3 VertexBuffers instances, so that's another memory leak.
Ok so there are some things you should fix in your code that cause memory leaks, and I just took a look on it, so you didn't really try. On the other hand, it seems your code is clear and full of explanations and I need to learn some DX11, so actually I should thank you for it. The downvote was somewhat rude though :P specially because I'm probably right, and other people would avoid reading your code as soon as the page displays.
Related
I have experience with D3D11 and want to learn D3D12. I am reading the official D3D12 multithread example and don't understand why the shadow map (generated in the first pass as a DSV, consumed in the second pass as SRV) is created for each frame (actually only 2 copies, as the FrameResource is reused every 2 frames).
The code that creates the shadow map resource is here, in the FrameResource class, instances of which is created here.
There is actually another resource that is created for each frame, the constant buffer. I kind of understand the constant buffer. Because it is written by CPU (D3D11 dynamic usage) and need to remain unchanged until the GPU finish using it, so there need to be 2 copies. However, I don't understand why the shadow map needs to do the same, because it is only modified by GPU (D3D11 default usage), and there are fence commands to separate reading and writing to that texture anyway. As long as the GPU follows the fence, a single texture should be enough for the GPU to work correctly. Where am I wrong?
Thanks in advance.
EDIT
According to the comment below, the "fence" I mentioned above should more accurately be called "resource barrier".
The key issue is that you don't want to stall the GPU for best performance. Double-buffering is a minimal requirement, but typically triple-buffering is better for smoothing out frame-to-frame rendering spikes, etc.
FWIW, the default behavior of DXGI Present is to stall only after you have submitted THREE frames of work, not two.
Of course, there's a trade-off between triple-buffering and input responsiveness, but if you are maintaining 60 Hz or better than it's likely not noticeable.
With all that said, typically you don't need to double-buffered depth/stencil buffers for rendering, although if you wanted to make the initial write of the depth-buffer overlap with the read of the previous depth-buffer passes then you would want distinct buffers per frame for performance and correctness.
The 'writes' are all complete before the 'reads' in DX12 because of the injection of the 'Resource Barrier' into the command-list:
void FrameResource::SwapBarriers()
{
// Transition the shadow map from writeable to readable.
m_commandLists[CommandListMid]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_shadowTexture.Get(), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE));
}
void FrameResource::Finish()
{
m_commandLists[CommandListPost]->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_shadowTexture.Get(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE));
}
Note that this sample is a port/rewrite of the older legacy DirectX SDK sample MultithreadedRendering11, so it may be just an artifact of convenience to have two shadow buffers instead of just one.
I implemented a loop with up to 100fps and can not spend more than 63fps.
What I believe is that the thread that runs the method of drawing opengl has a speed limit.
"(
#Override
public void onDrawFrame(GL10 gl)
)"
It depends on whether or not your rendering context has vertical sync enabled. Most LCD devices refresh at 60hz, and it may be waiting for the next refresh to call onDrawFrame(). That's one reason you'd be seeing that number.
The other possibility is that your draw is just taking long enough that it can't run any faster.
You should read the spec, for eglSwapInterval. It has to be implemented in your driver (I presume this is an Android device) to be able to see the effect. You can use it in any OpenGLES2 based application.
http://www.khronos.org/registry/egl/sdk/docs/man/xhtml/eglSwapInterval.html
A gist showing the usage here:
https://gist.github.com/prabindh/8467984
Is there a way to get a size of an opengl context? Or at least to estimate it's size? If yes, how?
I have an application in glut, which creates several windows. Since glut doesn't share opengl context between windows, every window is going to create new. Now, I am trying to reduce needed memory, since it is for an embedded system. But if the opengl context is small enough to neglect it, then I am not going to see big reduction in memory usage.
I have found this patch to create windows with shared opengl context :
A small addendum for Windows users (by Misbah Qidwai): I added this subroutine to glut_win.c. I use this routine to call wglSharedLists()
//MQ
/* CENTRY */
GLXContext APIENTRY
glutGetWindowRenderContext(int win)
{
GLUTwindow *window;
if (win < 1 || win > __glutWindowListSize) {
__glutWarning("glutSetWindow attempted on bogus window.");
return NULL;
}
window = __glutWindowList[win - 1];
if (!window) {
__glutWarning("glutSetWindow attempted on bogus window.");
return NULL;
}
return window->renderCtx;
}
A OpenGL context is an abstract thing. The amount of data backing a particular context can be as small as a pointer, or as big as a few megabytes. The context itself is not some kind of data structure, it's merely a handle shared by your program and the graphics system so that each other "knows" what the other is talking about.
The only way to know in a particular configuration is to measure it.
I noticed an odd memory increase in one of my Activities. Hence I ran a little test: I opened the dialog multiple times (open - close - open - close ....) and the memory kept increasing. So I used the DDMS to dump an HPROF file and opened it in MAT (Memory analyzer). The leak suspect report indicated, that the main reason for the growing memory consumption was this:
So I did a histogramm, to check that dialog I ran my tests on and what's keeping it alive. Turns out, it's kept alive by it's AutoCompleteTextViews, which in turn are kept alive by android.widget.TextView$IClipboardDataPasteEventImpl. However there are no immediate dominators for IClipboardDataPasteEventImpl (except of course the GC Root). I tried to find that IClipboardDataPasteEventImpl on the internet and I searched grepcode (the android source), but the only thing I could come up with was this blog entry. I can't read whatever language that is, but what I could read are the English words thrown in, which indicates, that it might be a bug on the Samsung Galaxy SII (the phone I am using, running android 2.3.x), related to the ClipboardManager. However I am unsure of this (I want to fix this, hence I am disinclined to simply accept it to be an unfixable bug) and I have no clue, where this Clipboard is spawned and why. I would greatly appreciate any pointers/ideas on the matter.
Investigation
Here're my research results:
It happens to any Activity whose content view consists of an EditText. finish()ing the Activity does not get it garbage collected as it is being referenced, like this:
activity com.example.MyActivity
<- mContext android.widget.TextView
<- this$0 android.widget.TextView$IClipboardDataPasteEventImpl
<- this$1 android.widget.TextView$IClipboardDataPasteEventImpl$1
<- referent java.lang.ref.FinalizerReference
It happens on my Samsung Galaxy Tab GT-P7300 running Android 4.0.4, but not on my Samsung Galaxy Mini GT-S5570 running Android 2.2.1.
The IClipboardDataPasteEventImpl objects eventually get freed, actually, but only at times which seems to be unpredictable.
Since they are referenced by java.lang.ref.FinalizerReference, I believe that the IClipboardDataPasteEventImpl objects are waiting to be finalize()'d, which happens only when the JVM feels like to. For details, check out these SO questions:
is memory leak? why java.lang.ref.Finalizer eat so much memory
Very strange OutOfMemoryError
Solution / Workaround
Sorry, no solution, but here's my best workaround:
In onDestroy() of your Activity, free as many references to other objects as possible (especially the big ones, such as bitmaps, collections, and child views of your activity), like this:
#Override
protected void onDestroy()
{
// Free reference to large objects.
m_SomeLargeObject = null;
m_AnotherLargeObject = null;
// For ArrayList, if you are a paranoid to null, you may call clear() and then trimToSize().
m_SomeLargeArrayList.clear();
m_SomeLargeArrayList.trimToSize();
// Free child views.
m_MyButton = null;
// Free adapters.
m_ListViewAdapter = null;
... etc.
// Don't forget to chain the call to the superclass.
super.onDestroy();
}
This way, we can at least reduce the casualties and hopefully won't go out of memory before the JVM has the mood to finialize and collect all those evil IClipboardDataPasteEventImpl objects.
In an ideal world of garbage collected environment, this would be unnecessary, but I guess we should all realize that our world is not perfect, and we just have to live with the flaws.
Below is my translation of the original blog entry (in Chinese) as mentioned in the question. Hopefully this can give everybody a better understanding about the issue.
Galaxy S2 memory leak with TextView
不知道是不是哪邊弄錯
Not sure where it went wrong
但是galaxy s2的textview會產生memory leak
But the textview of galaxy s2 causes memory leaks
leak是發生在android.widget.TextView$IClipboardDataPasteEventImpl這個interface上
Leak happens on the interface android.widget.TextView$IClipboardDataPasteEventImpl
它會抓住mContext造成整個activity沒辦法被gc
It holds the mContext, stopping the activity from being gc'ed
同樣的程式在htc sensation(2.3.4)跟se xperia arc(2.3.4)和acer liquid(2.1)都沒有問題
No such problem with the same app on htc sensation(2.3.4), se xperia arc(2.3.4) and acer liquid(2.1)
而且網路上完全找不到android.widget.TextView$IClipboardDataPasteEventImpl相關的資料
And, I can't find anything related to android.widget.TextView$IClipboardDataPasteEventImpl on the web at all
android source code裡也找不到 看起來應該是samsung自己加的東西...
Not even in the android source code, so it seems to be something added by samsung themselves...
之前的opengl viewport bug 已經夠頭痛了 接下來soundpool相關bug也搞累很多人
The opengl viewport bug was a headache already, and the soundpool related bug had frustrated many
現在這個memory leak又來攪局...
And now, here comes a memory leak messing around...
看來手機外型還是比較重要 /_\... 外型好先吸到人來買 bug再慢慢修就好
Seems that the appearance of mobile phones are more important /_\... good appearance attracts customers; bugs could be fixed later
[後記]
[P.S.]
經過一些試驗發現 只要按HOME button回到桌面,那些leak就會被釋放掉...
After some tests, I found out that the leaks will be freed by pressing the HOME button to go back to the desktop...
logcat會顯示一行Hide Clipboard dialog at Starting input: finished by someone else... !
It shows Hide Clipboard dialog at Starting input: finished by someone else... ! in logcat
看起來galaxy s2裡面有偷偷對clipboard作一些操作...
It seems that galaxy s2 is operating on the clipboard under the hood...
但如果一直保持在app裡面運作的話,那些leak還是會存在...最後應該會發生OOM exception
But if we stay in the app, those leaks remain... eventually an OOM exception would occur
現在只能期望galaxy s2 的ics版會修掉這個怪問題了...
Now we can only hope that this strange problem would be resolved in the ics version of galaxy s2...
My memleak investigation also brought me here. Im having problems with Activity leaking over EditText. android.widget.TextView$IClipboardDataPasteEventImpl object is holding the EditText which is holding the activity. This happens on Samsung Galaxy Tab 10.1, and Galaxy Tab 2 10.1, 7.0. I wasn't able to reproduce it on other non Samsung devices (Asus, Acer).
The bad thing is that I didn't find a solution for it yet :)
When in release it crashes with an unhandled exception: std::length error.
The call stack looks like this:
msvcr90.dll!__set_flsgetvalue() Line 256 + 0xc bytes C
msvcr90.dll!__set_flsgetvalue() Line 256 + 0xc bytes C
msvcr90.dll!_getptd_noexit() Line 616 + 0x7 bytes C
msvcr90.dll!_getptd() Line 641 + 0x5 bytes C
msvcr90.dll!rand() Line 68 C
NEM.exe!CGAL::Random::Random() + 0x34 bytes C++
msvcr90.dll!_initterm(void (void)* * pfbegin=0x00000003, void (void)* * pfend=0x00345560) Line 903 C
NEM.exe!__tmainCRTStartup() Line 582 + 0x17 bytes C
kernel32.dll!7c817067()
Has anyone got any clues?
Examining the stack dump:
InitTerm is simply a function that walks a list of other functions and executes each in step - this is used for, amongst other things, global constructors (on startup), global destructors (on shutdown) and atexit lists (also on shutdown).
You are linking with CGAL, since that CGAL::Random::Random in your stack dump is due to the fact that CGAL defines a global variable called default_random of the CGAL::Random::Random type. That's why your error is happening before main, the default_random is being constructed.
From the CGAL source, all it does it call the standard C srand(time(NULL)) followed by the local get_int which, in turn, calls the standard C rand() to get a random number.
However, you're not getting to the second stage since your stack dump is still within srand().
It looks like it's converting your thread into a fiber lazily, i.e., this is the first time you've tried to do something in the thread and it has to set up fiber-local storage before continuing.
So, a couple of things to try and investigate.
1/ Are you running this code on pre-XP? I believe fiber-local storage (__set_flsgetvalue) was introduced in XP. This is a long shot but we need to clear it up anyway.
2/ Do you need to link with CGAL? I'm assuming your application needs something in the CGAL libraries, otherwise don't link with it. It may be a hangover from another project file.
3/ If you do use CGAL, make sure you're using the latest version. As of 3.3, it supports a dynamic linking which should prevent the possibility of mixing different library versions (both static/dynamic and debug/nondebug).
4/ Can you try to compile with VC8? The CGAL supported platforms do NOT yet include VC9 (VS2008). You may need to follow this up with the CGAL team itself to see if they're working on that support.
5/ And, finally, do you have Boost installed? That's another long shot but worth a look anyway.
If none of those suggestions help, you'll have to wait for someone more knowledgable than I to come along, I'm afraid.
Best of luck.
Crashes before main() are usually caused by a bad constructor in a global or static variable.
Looks like the constructor for class Random.
Do you have a global or static variable of type Random? Is it possible that you're trying to construct it before the library it's in has been properly initialized?
Note that the order of construction of global and static variables is not fixed and might change going from debug to release.
Could you be more specific about the error you're receiving? (unhandled exception std::length sounds weird - i've never heard of it)
To my knowledge, FlsGetValue automatically falls back to TLS counterpart if FLS API is not available.
If you're still stuck, take .dmp of your process at the time of crash and post it (use any of the numerous free upload services - and give us a link) (Sounds like a missing feature in SO - source/data file exchange?)