Web 应用程序中 IronPython 内存泄漏问题
有没有人在 Web 环境中成功运行 IronPython 而没有出现问题?我遇到了一些问题。
第一个问题,我实际上并没有运行任何特定于 IronPython 的脚本,我正在实现 Pygments 库,这样我就可以获得服务器 -侧面语法突出显示。该库大约有 20 多个文件。
除此之外,最新的 IronPython 版本无法将脚本编译为 DLL(由于此问题) ,我只需将所有文件和依赖项复制到我的 bin 文件夹即可成功运行。
问题是,我查看了 w3wp.exe 进程在突出显示时的表现,并注意到一些令人震惊的问题:
即使在 Cassini 下的完全基本的空网站中,突出显示代码
select * from使用 SQL 词法分析器的 table
每次执行它都会导致 10MB 跳转(页面刷新)...我显式关闭引擎并在单个函数调用中使用LightweightScopes
。它的起始大小约为 30MB,经过大约 20 次刷新后,大小达到 150MB 左右。在我的实际 Web 应用程序中,使用 SQL 词法分析器(相同的代码)会导致我的应用程序池增加约 200MB/秒(实际上,当它达到约 1GB 时我会杀死它),直到它崩溃 w3wp 或使我的 PC 速度减慢至爬行。这在空测试站点中不会发生,并且在具有相同确切代码的控制台应用程序中根本没有问题。其他词法分析器(如 C#)不会导致巨大的内存泄漏,但确实会在每次调用函数时增加内存,从而产生相同的效果。
这让我相信这是一个特定于 Web 的问题,考虑到控制台应用程序没有任何问题(实例化运行时确实会导致内存增加 20MB)。
我正在使用 Pygments 的 2.7 IPY 版本和 1.4 版本。
我目前没有确切的代码,但它看起来像:
var options = something;
options["LightweightScopes"] = ScriptRuntimeHelpers.True; // from another SO post, 'true' didn't seem to work
var engine = Python.CreateEngine(options);
//
// set up search paths here...
//
dynamic scope = whatever;
ScriptSource source = engine.CreateScriptSourceFromFile("myscript.py");
// Execute? Compile? It populates the scope at this point...
source.Compile(scope);
// execute (code, lexer name, style)
// this is a python function I have that calls the Pygments code
var highlighted = scope.generate_html("select * from table", "sql", "monokai");
engine.Shutdown();
return highlighted;
就像我说的,我将相同的代码复制到:a)控制台应用程序,b)全新的空网络应用程序,c)我的原始网络应用程序。控制台应用程序不会泄漏内存,但网络应用程序会泄漏内存。
我还使用本机 Python (python myscript.py
) 和 IPY (ipy myscript.py
) 执行该函数,并且都没有任何内存泄漏。
我是否缺少一些处理运行时的最佳实践?我计划在共享环境中运行它,因此在不同的应用程序池中实例化引擎的可能解决方法可能对我不起作用(此外,200MB/s 的巨大泄漏有点令人震惊)。
目前,除非有人有灵丹妙药,否则我打算废弃我的代码,只使用 Javascript 语法荧光笔。这真的很不幸,因为 Pygments 太棒了......
Has anyone successfully gotten IronPython running without issues in a web environment? I am running into some issues.
First issue, I am not actually running any IronPython-specific scripts, I am implementing the Pygments library so I can get server-side syntax highlighting. The library is about 20+ files.
Besides the fact that the latest IronPython release cannot compile the scripts into a DLL (due to this issue), I do have it running successfully by just copying all the files and dependencies to my bin folder.
The problem is, I went to look at how my w3wp.exe process is doing when doing highlighting and noticed some showstopper issues:
Even in a totally basic, empty web site under Cassini, highlighting the code
select * from table
using the SQL lexer causes a 10MB jump every time I execute it (page refresh)... I am explicitly shutting down the engine and usingLightweightScopes
in a single function call. It starts at about 30MB and with about 20 refreshes it's at 150MB or so.In my actual web application, using the SQL lexer (same code) causes my app pool to increase about 200MB/sec (literally, I kill it when it reaches about 1GB) until it either crashes w3wp or slows my PC down to a crawl. This doesn't happen in the empty test site and there are no problems at all in a console app with the same exact code. Other lexers like C# do not cause the huge memory leak but do have the same effect of increasing the memory each time you call the function.
This leads me to believe this a web-specific issue, considering the console app doesn't have any problems (instantiating the runtime does cause a 20MB increase in memory, though).
I am using the 2.7 IPY release and 1.4 release of Pygments.
I don't have the exact code with me at the moment but it looks something like:
var options = something;
options["LightweightScopes"] = ScriptRuntimeHelpers.True; // from another SO post, 'true' didn't seem to work
var engine = Python.CreateEngine(options);
//
// set up search paths here...
//
dynamic scope = whatever;
ScriptSource source = engine.CreateScriptSourceFromFile("myscript.py");
// Execute? Compile? It populates the scope at this point...
source.Compile(scope);
// execute (code, lexer name, style)
// this is a python function I have that calls the Pygments code
var highlighted = scope.generate_html("select * from table", "sql", "monokai");
engine.Shutdown();
return highlighted;
Like I said, I copied this same code in: a) a console app, b) a brand new empty web app, c) my original web app. The console app did not leak memory, but the web apps do.
I also executed the function with both the native Python (python myscript.py
) and IPY (ipy myscript.py
) and neither had any memory leaks.
Is there some best practice I am missing to dispose of the runtime? I plan on running this in a shared environment, so the possible workaround of instantiating the engine in a different app pool probably won't work for me (also, that huge leak with the 200MB/s is kind of a showstopper).
Currently, unless someone has a miracle cure, I plan to scrap my code and just go with a Javascript syntax highlighter. It's real unfortunate because Pygments is awesome...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是一个很长的故事。 (TLDR,抱歉)。对于 .NET,您很可能会看到堆碎片而不是内存耗尽。
如果你确实泄漏了内存,那么你保留引用的时间太长了。检查 IDisposables(尤其是列表理解可能会造成伤害,尤其是附加了像 orderby 和 unique 这样的 Linqy 东西)。
我曾经使一个应用程序的运行速度提高了 2 倍,当时它通过在必须驱动一个大进程的最大枚举上添加一个简单的 .ToList() 来耗尽/碎片化堆而可靠地失败。
.NET 有很好的内存分析器,但我目前只知道如何操作 mono --profiler(内存不好)。一个简单的谷歌将帮助您找到一个可以在您的环境中使用的分析器:让它准确地告诉您分配给您的堆
PS 碎片的哪些对象。因为我看到您在第二次扫描您的问题时将矛头指向了 Web 应用程序,所以我想补充一点:检查会话状态(应用程序、会话)中持有哪些引用(间接)。
That's quite a long story. (TLDR, sorry). This being .NET, you're most likely looking at heap fragmentation rather than memory exhaustion.
If you are really leaking memory then you are holding on to references too long. Review you IDisposables (especially list comprehension can hurt, especially with Linqy things like orderby and distinct tacked on).
I once made an application run 2x as fast, when it was reliably failing by exhausting/fragmenting the heap by tacking a simple .ToList() on the largest enumerations I had to drive a big process.
There are good memory profilers for .NET, but I currently know how to operate only mono --profiler (bad memory). A simple google will help you find a profiler you can use on your environment: let it tell you exactly what objects allocated where are fragmenting your heap
PS. since I saw you pointing the finger on Web applications on second scanning of your question, I would add: check what references (indirectly) are being held from Session state (application, session).