2

TL;DR: Is an IOSurfaceRef a valid surface to write to after it has been purged and its state changed to kIOSurfacePurgeableEmpty?


I'm trying to get a better understanding of what it means for an IOSurface to be purged. The only documentation I have come across is in IOSurfaceRef.h and the only sample code I've come across is in WebKit.

I'm using the command line tool memory_pressure to simulate a critical memory pressure environment for 10 seconds like so:

> memory_pressure -S -s 10 -l critical

I've written a very simple application that allocates 100 IOSurfaces with identical properties. When I use Instruments to measure the memory allocations, I see VM: IOSurface at roughly 6GB, which is about 6MB for each surface. (4096x4096x4)

I then change the purgeable state of each IOSurface to kIOSurfacePurgeableVolatile and run the memory_pressure simulation.

Instruments still reports that I have 6GB of surfaces allocated. However, if I check the purgeable state of each surface, they are marked as kIOSurfacePurgeableEmpty.

So it looks like they were successfully purged, but the memory is still allocated to my application. Why is that and what condition are these surfaces in?

The header file states that I should assume they have "undefined content" in them. Fair enough.

But is the actual IOSurfaceRef or IOSurface * object still valid? I can successfully query all of its properties and I can successfully lock it for reading and writing.

Am I allowed to just reuse that object even though its contents were purged or do I have to discard that instance and create an entirely new IOSurface?

macos 10.14

kennyc
  • 5,490
  • 5
  • 34
  • 57

1 Answers1

2

Yes, it's still usable. It's just that the pixel data has been lost.

Basically, when the system is under memory pressure, it would normally page data out to disk. Marking a purgeable object volatile allows the system to simply discard that data, instead. The app has indicated that while it's nice-to-have, it's not has-to-have, and can be recreated if necessary.

When it wants to work with the IOSurface again, the app should mark the object nonvolatile and check the old state. If it was empty, then the app should recreate the data.

The reason that Instruments reports that your app still has 6GB allocated is because it has 6GB of its address space reserved for the IOSurfaces. But allocated does not necessarily mean backed by either physical RAM or swap file. It's just bookkeeping until the memory is actually used. Your app's resident set size (RSS) should shrink.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • That's what I sort of concluded, but there's one thing I still don't understand. If the system was under real memory pressure and my surface was purged, then presumably some other process "took" that memory for its own use. If I then request it "back" by marking my surface as non-volatile, then what happens if the system is unable to reclaim the memory? I don't see any IOSurface API that indicates a purged surface couldn't be reallocated, so I must not understand something. Does the VM just page everything else out to disk until I get my 6GB "back"? – kennyc Feb 06 '19 at 20:24
  • 1
    Basically, yes. That's the general behavior of virtual memory. In extreme cases of VM use, you can get [thrashing](https://en.wikipedia.org/wiki/Thrashing_(computer_science)). On modern OSes, an allocation never fails due to a lack of memory, only lack of address space. And, for 64-bit processes, that almost never happens, either. For this `IOSurface` situation, the address space was already allocated, anyway. – Ken Thomases Feb 06 '19 at 20:58