Swift pointer problems with MACH_TASK_BASIC_INFO
When interacting with C functions, you can't rely on the compiler's error messages - break it down parameter by parameter, command-clicking until you know what you're working with. To start with, the types you're running into are:
task_name_t
:UInt32
task_flavor_t
:UInt32
task_info_t
:UnsafeMutablePointer<Int32>
UnsafeMutablePointer<mach_msg_type_number_t>
:UnsafeMutablePointer<UInt32>
kern_return_t
-Int32
There's one tricky Swift bit along with a bug in your code standing in your way here. First, the task_info_out
parameter needs to be a UnsafeMutablePointer<UInt32>
, but needs to actually point to an instance of mach_task_basic_info
. We can get around this by creating a UnsafeMutablePointer<mach_task_basic_info>
and wrapping it in another UnsafeMutablePointer
at call time - the compiler will use type inference to know we want that wrapping pointer to be sub-typed as UInt32
.
Second, you're calling sizeof(mach_task_basic_info_t)
(the pointer to mach_task_basic_info
) when you should be calling sizeinfo(mach_task_basic_info)
, so your byte count ends up too low to hold the data structure.
On further research, this got a little more complicated. The original code for this was incorrect, in that size
should be initialized to the constant MACH_TASK_BASIC_INFO_COUNT
. Unfortunately, that's a macro, not a simple constant:
#define MACH_TASK_BASIC_INFO_COUNT (sizeof(mach_task_basic_info_data_t) / sizeof(natural_t))
Swift doesn't import those, so we'll need to redefine it ourselves. Here's working code for all this:
// constant
let MACH_TASK_BASIC_INFO_COUNT = (sizeof(mach_task_basic_info_data_t) / sizeof(natural_t))
// prepare parameters
let name = mach_task_self_
let flavor = task_flavor_t(MACH_TASK_BASIC_INFO)
var size = mach_msg_type_number_t(MACH_TASK_BASIC_INFO_COUNT)
// allocate pointer to mach_task_basic_info
var infoPointer = UnsafeMutablePointer<mach_task_basic_info>.alloc(1)
// call task_info - note extra UnsafeMutablePointer(...) call
let kerr = task_info(name, flavor, UnsafeMutablePointer(infoPointer), &size)
// get mach_task_basic_info struct out of pointer
let info = infoPointer.move()
// deallocate pointer
infoPointer.dealloc(1)
// check return value for success / failure
if kerr == KERN_SUCCESS {
println("Memory in use (in bytes): \(info.resident_size)")
} else {
let errorString = String(CString: mach_error_string(kerr), encoding: NSASCIIStringEncoding)
println(errorString ?? "Error: couldn't parse error string")
}
Watching memory usage in iOS
While testing and debugging your app with XCode you can use this logMemUsage()
function to NSLog the used/free space and watch how things are going while you test your app. This function logs any change in usage > 100kb. It outputs to the debug log like this (on the simulator the free space is huge):
2011-11-02 21:55:58.928 hello[971:207] Memory used 21884.9 (+21885), free 1838366.8 kb
2011-11-02 21:55:59.936 hello[971:207] Memory used 28512.3 (+6627), free 1830809.6 kb
2011-11-02 21:56:01.936 hello[971:207] Memory used 28803.1 ( +291), free 1830129.6 kb
2011-11-02 21:56:02.936 hello[971:207] Memory used 29712.4 ( +909), free 1830142.0 kb
You decide where to call logMemUsage
in your app. I happen to have a function that is called by a timer every second and so I put it in there. I suggest using #ifdef
around these so this code is only included in Debug builds.
#import "mach/mach.h"
vm_size_t usedMemory(void) {
struct task_basic_info info;
mach_msg_type_number_t size = sizeof(info);
kern_return_t kerr = task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)&info, &size);
return (kerr == KERN_SUCCESS) ? info.resident_size : 0; // size in bytes
}
vm_size_t freeMemory(void) {
mach_port_t host_port = mach_host_self();
mach_msg_type_number_t host_size = sizeof(vm_statistics_data_t) / sizeof(integer_t);
vm_size_t pagesize;
vm_statistics_data_t vm_stat;
host_page_size(host_port, &pagesize);
(void) host_statistics(host_port, HOST_VM_INFO, (host_info_t)&vm_stat, &host_size);
return vm_stat.free_count * pagesize;
}
void logMemUsage(void) {
// compute memory usage and log if different by >= 100k
static long prevMemUsage = 0;
long curMemUsage = usedMemory();
long memUsageDiff = curMemUsage - prevMemUsage;
if (memUsageDiff > 100000 || memUsageDiff < -100000) {
prevMemUsage = curMemUsage;
NSLog(@"Memory used %7.1f (%+5.0f), free %7.1f kb", curMemUsage/1000.0f, memUsageDiff/1000.0f, freeMemory()/1000.0f);
}
}
Virtual functions and performance - C++
A good rule of thumb is:
It's not a performance problem until you can prove it.
The use of virtual functions will have a very slight effect on performance, but it's unlikely to affect the overall performance of your application. Better places to look for performance improvements are in algorithms and I/O.
An excellent article that talks about virtual functions (and more) is Member Function Pointers and the Fastest Possible C++ Delegates.
Ways to eliminate switch in code
Switch-statements are not an antipattern per se, but if you're coding object oriented you should consider if the use of a switch is better solved with polymorphism instead of using a switch statement.
With polymorphism, this:
foreach (var animal in zoo) {
switch (typeof(animal)) {
case "dog":
echo animal.bark();
break;
case "cat":
echo animal.meow();
break;
}
}
becomes this:
foreach (var animal in zoo) {
echo animal.speak();
}
Related Topics
How String Comparison Happens in Swift
Propagate an Optional Through a Function (Or Init) in Swift
Re-Initialize a Lazy Initialized Variable in Swift
Mathematical Functions in Swift
Pull Down to Refresh Data in Swiftui
Swift: Print Decimal Precision of Division
In Xcode 6.1. 'Uiimage' Does Not Have a Member Named 'Size' Error
Change the Value That Is Being Set in Variable's Willset Block
Swift Alternative to Performselectoronmainthread
What Are the Rules for Spaces in Swift
Swift 2 iOS 9 Do Catch Try Crashing with Unexpected Nil Found
App Tracking Transparency Dialog Does Not Appear on iOS
Uicollectionview - Resizing Cells on Device Rotate - Swift
Dispatchsourcetimer and Swift 3.0
Alamofire Asynchronous Completionhandler For Json Request
Module Compiled With Swift 3.0 Cannot Be Imported in Swift 3.0.1
Extension May Not Contain Stored Property But Why Is Static Allowed