Batch Deleting Entity Types
I decided to bite the bullet and run everything with Batch API. This meant the site was painfully slow for probably 2-3 hours, then slow for another hour or so. The profile type deletions became faster as there were fewer left to delete (since cache rebuilds were less intense the fewer field instances that were required).

I set up the batch using something like the following:

// You can remove the limit if you want, but this is a very long operation,
// so it's nice to do it in smaller chunks during traffic lulls.
$types = db_query("SELECT type FROM {profile_type} LIMIT 100")-&gt;fetchCol();
$batch = array(
  'operations' =&gt; array(
    array('mymodule_bulk_delete_profile_types', array($types))
  ),
  'finished' =&gt; 'mymodule_bulk_delete_profile_types_finished',
  'title' =&gt; t('Removing Profile Types'),
  'init_message' =&gt; t('Beginning profile type deletion...'),
  'progress_message' =&gt; t('Deleting profile types...'),
  'file' =&gt; drupal_get_path('module', 'fn_profile') . '/includes/fn_profile.utility.inc',
);
batch_set($batch);
batch_process();


Then, I had two batch callbacks (the processing function and the finished function), like so:

function mymodule_bulk_delete_profile_types($types, &amp;$context) {
  $context['finished'] = 0;

  if (!isset($context['sandbox']['progress'])) {
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['max'] = count($types);
    $context['results']['count'] = 1;
  }

  if (!isset($context['sandbox']['types'])) {
    $context['sandbox']['types'] = $types;
  }

  $key = $context['results']['count'] - 1;
  $type_to_delete = $context['sandbox']['types'][$key];
  $profile_type = profile2_get_types($type_to_delete);
  profile2_type_delete($profile_type);

  $context['results']['count']++; // Increment the counter.
  $context['finished'] = $context['results']['count'] / $context['sandbox']['max'];

  // Show message updating user on how many profile types have been deleted.
  $context['message'] = t('Deleted @count of @total profile types.', array(
    '@count' =&gt; $context['results']['count'],
    '@total' =&gt; $context['sandbox']['max'],
  ));
}

function mymodule_bulk_delete_profile_types_finished($success, $results, $operations) {
  // Display any warnings.
  if (!empty($results['warnings'])) {
    foreach ($results['warnings'] as $warning) {
      if ($warning) {
        drupal_set_message($warning, 'warning');
      }
    }
  }
  // Set operation successful message.
  if ($success) {
    if ($results['count'] == 0) {
      $message = t("No profile types were deleted.");
    } else {
      $message = t("@count profile types deleted successfully.", array('@count' =&gt; $results['count']));
    }
  } else {
    $message = t("There were problems deleting profile types.");
  }
  drupal_set_message($message, 'status');
}


At the beginning, it was taking between 50 seconds and 80 seconds to delete a profile type. Towards the end of the batch, it was only taking about 20-30 seconds. The site now only uses about 30-40 MB (according to devel.module) when clearing all caches; it was using about 190 MB before, and taking over 2 minutes to rebuild the caches!