Skip to content

Truncated MemoryError exception message when importing too-large .py #569

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
dhalbert opened this issue Feb 1, 2018 · 18 comments
Closed
Milestone

Comments

@dhalbert
Copy link
Collaborator

dhalbert commented Feb 1, 2018

This is very odd:

  1. Get the .py version of the CPX library: https://github.com/adafruit/Adafruit_CircuitPython_CircuitPlayground/releases/download/1.2.0/adafruit-circuitpython-circuitplayground-py-1.2.0.zip
  2. Unzip it and put the adafruit_circuitplayground directory at the top level of CIRCUITPY
  3. In the repl, try to import it. It's too big to compile, as expected. But note that the Memory Error: is incomplete.
Adafruit CircuitPython 2.2.1 on 2018-01-23; Adafruit CircuitPlayground Express with samd21g18
>>> from adafruit_circuitplayground.express import cpx
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError: 
>>> 
  1. Now move the adafruit_circuitplayground directory into the lib directory, and restart the board.
  2. Import it again in the REPL:
Adafruit CircuitPython 2.2.1 on 2018-01-23; Adafruit CircuitPlayground Express with samd21g18
>>> from adafruit_circuitplayground.express import cpx
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError: memory allocation failed, allocating 338 bytes

Note the differences in the exception message.

I've tried to make a simpler test case and haven't succeeded yet. T module's position on sys.path makes a difference. But it should not.

@dhalbert dhalbert added this to the 2.x milestone Feb 1, 2018
@dhalbert
Copy link
Collaborator Author

dhalbert commented Feb 1, 2018

The truncated Memory Error: message occurs as far back as 2.0.0, but it's OK in 1.0.0.

@dhalbert
Copy link
Collaborator Author

dhalbert commented Feb 1, 2018

The placement in sys.path is not always the issue, and may be a red herring. Here are more oddities, testing with various versions.
In this case the library is in lib/. If I make a typo on the first import, then the correct import does not do the printf expansion:

Adafruit CircuitPython 3.0.0-alpha.1-109-g7c6adaa66-dirty on 2018-02-01; Adafruit CircuitPlayground Express with samd21g18
>>> 
>>> from adafruit_circuitplayground import cpx
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: no module named 'adafruit_circuitplayground.cpx'
>>> from adafruit_circuitplayground.express import cpx
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError: memory allocation failed, allocating %u bytes
Adafruit CircuitPython 3.0.0-alpha.1-109-g7c6adaa66-dirty on 2018-02-01; Adafruit CircuitPlayground Express with samd21g18
>>> from adafruit_circuitplayground.express import cpx
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError: memory allocation failed, allocating 338 bytes

I suspect some free-before-use problem or smashed register or similar.

@tannewt
Copy link
Member

tannewt commented Feb 1, 2018

I don't think we need to fix this in 2.x. I'd only fix crashes in 2.x at this point. Lets shoot to have this done as polish on 3.0. Please change the milestone if you agree.

@dhalbert
Copy link
Collaborator Author

dhalbert commented Feb 1, 2018

I'll debug it in 3.0. If it's a serious memory problem I'll backport.

@dhalbert dhalbert modified the milestones: 2.x, 3.0 Feb 1, 2018
@dhalbert dhalbert changed the title Truncated exception message when importing too-large .py at top-level Truncated MemoryError exception message when importing too-large .py Feb 1, 2018
@tannewt
Copy link
Member

tannewt commented Feb 1, 2018 via email

@jallwine
Copy link

I'm seeing similar weirdness developing my own python library. Subtle, seemingly innocuous changes trigger a MemoryError exception. I don't have a solid test case, but in an attempt to track things down I've put a print(gc.mem_free() / 1024) my main code.py file and started commenting out swaths of code in the library that it's importing. It'll print >10K of memory left in one run, but uncommenting a msg = "" all of sudden triggers a MemoryError exception. It's repeatable for a few runs, but then works fine. Seems like something insidious is going on...

@deshipu
Copy link

deshipu commented Feb 21, 2018

That's effects of memory fragmentation, most likely — you don't only need to have that much memory free, you have to have it all in one chunk to allocate it.

@jallwine
Copy link

That makes sense, is there a recommended process for limiting fragmentation? Reseting the board more often?

@deshipu
Copy link

deshipu commented Feb 21, 2018

Reset works, of course. There also has been some awesome work in #547 to improve the situation.

@jallwine
Copy link

Awesome! Seems that this is worth a mention in a troubleshooting page somewhere. This isn't something that's regularly encountered in your every day python development.

@dhalbert
Copy link
Collaborator Author

There's no memory state saved between resets, so it starts from scratch after each reset. #547 will help a lot. For now, two things to do are perhaps to load larger modules first, and compile (mpy-cross) as many modules as you can, so you don't have to compile to bytecodes on chip.

@jallwine
Copy link

Thanks @dhalbert. Could you clarify what a reset is? Pressing the reset button? Power cycling the board? The soft reboot that happens after saving your code.py or library file?

@tannewt
Copy link
Member

tannewt commented Feb 22, 2018

@jallwine @dhalbert means the soft reload that happens on save.

As @deshipu points out, we have improvements in master (future 3.0.0) that could help a bunch.

@deshipu
Copy link

deshipu commented Feb 25, 2018

I just hit the "MemoryError: memory allocation failed, allocating %u bytes" error on MicroPython, so I think this is actually an upstream bug.

@deshipu
Copy link

deshipu commented Feb 25, 2018

So I looked at the code that actually creates the exceptions, and it seems that this is not a bug, this is a feature: https://github.com/adafruit/circuitpython/blob/master/py/objexcept.c#L417-L435

Basically, if there is not enough memory to format the string, it will stay un-formated, and if there is no room to even allocate the string, the exception will have no string at all.

@dhalbert
Copy link
Collaborator Author

@deshipu Thanks for doing the research on this. I thought it might be lack of memory but didn't think it would be intentional. I wonder if we should have a fixed string to return that indicates lack of memory. @tannewt

@tannewt
Copy link
Member

tannewt commented Feb 27, 2018

The behavior now is fine with me. It is useful knowing the size of the allocation that fails when its possible to. They can all be caught through MemoryError so they should be essentially equivalent.

Anyone have a different suggestion?

@tannewt
Copy link
Member

tannewt commented May 14, 2018

I'm ok with how this works now and no one objected. :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants