This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author Jack Liu
Recipients Jack Liu, brett.cannon, eric.snow, ncoghlan
Date 2016-09-20.05:48:35
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1474350515.81.0.126049565271.issue28202@psf.upfronthosting.co.za>
In-reply-to
Content
I wrote the test code as below. I also attached the files in attachment.
Python
=========================================================

class Simple:
     def __init__( self ):
         print('Simple__init__')
     def __del__( self ):
         print('Simple__del__')

simple = None

def run():
    global simple
    simple = Simple()

if __name__ == '__main__':
	run()
==============================================================

C++
=========================================================================

#include "stdafx.h"
#include <Python.h>
#include <string>
#include <iostream>
#include <fstream>
#include <codecvt>
#include <map>

using namespace std;

namespace {
	wstring readfile(const wchar_t *filename)
	{
		wifstream wifs;

		wifs.open(filename);
		//wifs.imbue(locale(wifs.getloc(), new codecvt_utf8<wchar_t, 0x10ffff, consume_header>()));
		wstring wstr((std::istreambuf_iterator<wchar_t>(wifs)),
			std::istreambuf_iterator<wchar_t>());
		return wstr;
	}

	string wstrtostr(const wstring& ws)
	{
		std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
		return converter.to_bytes(ws);
	}
}

int main()
{
	cout << "Input py file full path:" << endl;
	wstring filePath;
	wcin >> filePath;
	//filePath = L"L:\\Dev\\PyTest\\SimpleTest.py";

	string moduleName = "__main__";

	string script = wstrtostr(readfile(filePath.c_str()));
	if (script.empty())
	{
		cout << "Invalid python file path" << endl;
		return 1;
	}

	string sfileName = wstrtostr(filePath);

	// Initialize the Python Interpreter
	Py_Initialize();

	PyObject *py_module = PyImport_AddModule(moduleName.c_str());
	PyObject *py_dict = PyModule_GetDict(py_module);

	PyObject* res = nullptr;
	auto arena = PyArena_New();
	if (arena)
	{
		auto mod = PyParser_ASTFromString(script.c_str(), sfileName.c_str(), Py_file_input, nullptr, arena);
		if (mod)
		{
			auto co = PyAST_Compile(mod, sfileName.c_str(), nullptr, arena);
			if (co)
			{
				res = PyEval_EvalCode((PyObject*)(co), py_dict, py_dict);
				Py_DECREF(co);
			}
		}
		PyArena_Free(arena);
	}
	if (res)
	{
		Py_DECREF(res);
	}

	// Delete the module from sys.modules
	PyObject* modules = PyImport_GetModuleDict();
	cout << "PyDict_DelItemString" << endl;
	PyDict_DelItemString(modules, moduleName.c_str());

	// May run many scripts here

	// Finish the Python Interpreter
	cout << "Py_Finalize" << endl;
	Py_Finalize();

	return 0;
}
===================================================================

The expected output in console should be:
Simple__init__
PyDict_DelItemString
Simple__del__
Py_Finalize

I tested with Python 3.2.5, 3.3.5, 3.5.1 and 3.6.0 beta.
It worked as expected with Python 3.2.5 and 3.3.5, but did not work Python 3.5.1 and 3.6.0 beta.

On Python 3.5.1 and 3.6.0 beta, the output is:
Simple__init__
PyDict_DelItemString
Py_Finalize
Simple__del__
That means the Simple object is not released at PyDict_DelItemString, it's released at Py_Finalize.

So it it a regression bug since Python 3.5? I wish there is a solution to resolve memory leak issue.
History
Date User Action Args
2016-09-20 05:48:35Jack Liusetrecipients: + Jack Liu, brett.cannon, ncoghlan, eric.snow
2016-09-20 05:48:35Jack Liusetmessageid: <1474350515.81.0.126049565271.issue28202@psf.upfronthosting.co.za>
2016-09-20 05:48:35Jack Liulinkissue28202 messages
2016-09-20 05:48:35Jack Liucreate