Possible memory leak in AlsaSink #127
Comments
This is a long track of 32 minutes. Still, I don't like the fact that the memory usage stays high after playback is stopped and the track unloaded. Can you observe the same memory growth if you don't connect an audio sink, but instead just ask libspotify to prefetch the audio data using session.player.prefetch(track)? How is memory usage when you unload the track again? |
I tried to illustrate the problem using continuous playback - hence the long track - in hindsight the buffer size would be a lot larger to accommodate the larger file. My bad! Anyway, I'll post my findings using prefetch shortly!
|
|
After session.player.play(False):
After session.player.unload():
|
Once the track has been stopped and unloaded the memory consumption stops, but it doesn't appear to free up. |
Your example doesn't tell if the memory usage grows at If there's no memory leak with just This will help pinpoint if the memory leak is in libspotify/prefetch, the pyspotify event system, or in |
Does this help? richard@raspberrypi-> python3
Python 3.2.3 (default, Mar 1 2013, 11:53:50)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import spotify
>>> session = spotify.Session()
>>> loop = spotify.EventLoop(session)
>>> loop.start()
>>> session.login('xanox','xxx')
>>> track = session.get_track('spotify:track:13qqdlSeF8FcxsRyapDMZ0')
>>> track.load()
Track('spotify:track:13qqdlSeF8FcxsRyapDMZ0')
>>> session.player.prefetch(track)
>>> session.player.load(track)
>>> session.player.play()
>>> audio = spotify.AlsaSink(session)
A short debug output
|
I agree, this clearly shows |
Just a hunch, but it could be to do with: |
The The size of this bytestring is in the range of 4_2048 to 4_22050 bytes per audio delivery, depending on their frequency. Per second, we're talking about 4*44100=176400 bytes of data that is copied once from libspotify to Python and then passed on to ALSA, probably causing a second copy. No references to this data is kept for later, so the total memory usage from this pipeline shouldn't be growing over time. |
I've tested a bit myself now, and I can see that the memory usage grows when importing |
Can you supply the other of commands you used so I can test on my Pi? |
I've just used With the exception of my choice of a shorter track, I've done exactly the same as you've done above. |
One thing you can try just for debugging is: after having played a track, and audio._close() |
|
I thought, as I'm using Raspian's hard float armv6 version of libspotify (which is currently in beta), it may be an issue within the libspotify source. But, having run jukebox.c for an extended period of time, the memory usage was fairly stable. |
Any further pointers to try and debug this one? |
I'm planning to try to reproduce this on one of my own Raspberry Pis, and with longer tracks now when I'm back on proper Internet. |
I've now tried to reproduce on a Raspberry Pi running Raspbian (armhf, in other words) updated a couple of days ago. I used pyspotify2 as of today, commit f528745. Exact command executed was:
This command requires that you already have cached credentials in place, which you can create like this: >>> import spotify
>>> session = spotify.Session()
>>> loop = spotify.EventLoop(session)
>>> loop.start()
>>> session.login('me', 'secret', remember_me=True) # The `remember_me` part is important
>>> session.connection.state
<ConnectionState.LOGGED_IN: 1>
>>> spotify.logout() # Important for proper flushing to disk
>>> session.connection.state
<ConnectionState.LOGGED_OUT: 0> The track used lasts for 79 minutes, which should be enough to make most memory leaks visible. Before I started Python, memory usage was at 84MB ( In other words, I'm not able to reproduce this issue. |
With a brand new pi + new install of Raspbian Wheezy the memory usage isn't any better.. what versions of pyalsaudio and stuff are you running? |
|
different versions so i'll try getting those upgraded. |
Just got a new SD card and it's still an issue. What's in your /etc/apt/sources.list?
my apt doesn't find 1.0.27.2-3 for alsa-utils. |
It would appear that Python 3.2.3 is the culprit. Running your suggested commands on Python 2.7.3 gives me much better memory (and CPU) stability! |
Great! I can reproduce on Python 3.3 and 3.4. Will look more into this. For the record, I'm running the testing/jessie version of Raspbian. My
|
Test SetupTesting on MacBook Air 2011 model, running Ubuntu 14.04 amd64. pyspotify v2.0.0b3 and all dependencies are installed in virtualenvs, including pyalsaaudio 0.7. Tested using
Results
Conclusion: The memory leak is clearly in the ALSA part, and not elsewhere in pyspotify or in pyspotify's event system delivering the audio data to the Reproducing with just pyalsaaudioI created the following script to try to reproduce the issue without pyspotify involved: from __future__ import print_function
import resource
import time
import alsaaudio
seconds = 0
max_rss = 0
device = alsaaudio.PCM()
while True:
device.write(b'\x00' * 44100)
time.sleep(1)
seconds += 1
if seconds % 10 == 0:
prev_rss = max_rss
max_rss = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
diff_rss = max_rss - prev_rss
print('After %ds: max RSS %d kB, increased %d kB' % (
seconds, max_rss, diff_rss)) Which gave the following results on Python 2.7.6:
And on Python 3.4.0:
The growth seems to be about (15416kB - 8252kB) / (180s - 10s) = 42.14 kB/s. This is peculiarly close to the 43.07 kB (44100 bytes / 1024) of fake audio data we throw at pyalsaaudio every second. With pyspotify, we throw four times as much data on pyalsaaudio (16-bit stereo audio, not 8-bit mono like we fake here), so the memory growth will probably be four times faster in real life. |
I can confirm that the memory leak also is present on Python 3.2.5:
If I quadruple the amount of audio data, the memory growth quadruples as well:
|
Bug reported upstream at https://sourceforge.net/p/pyalsaaudio/bugs/16/ |
This bug was fixed today in larsimmisch/pyalsaaudio@5e8a08b. |
Over a 15 minute window I checked the memory usage:
Then, after stopping and unloading the player:
The text was updated successfully, but these errors were encountered: