Clear cache doesn't clear the cache tables?
Can I just truncate all cache_... tables?


You should not truncate the "cache_form" table, as it contains the data used from Drupal to validate them; if you delete that table, the form currently being submitted from the user would be invalidated, and the users would need to submit the form again.  

There could be some other cache tables that cause a module to act strangely. That is the reason modules that are using extra cache tables (whose name generally starts with "cache_") are supposed to implement hook_flush_cache() to return the cache tables that can be cleared from Drupal, and which is then called with the following code, from drupal_flush_all_caches().

  $core = array('cache', 'cache_path', 'cache_filter', 'cache_bootstrap', 'cache_page');
  $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
  foreach ($cache_tables as $table) {
    cache_clear_all('*', $table, TRUE);
  }


drupal_flush_all_caches() is the function called from system_clear_cache_submit(), the submission form handler called when you click on the "Clear all caches" button, in the performance settings page.

During cron tasks, system_cron() clears the cache using the following code.

  $core = array('cache', 'cache_path', 'cache_filter', 'cache_page', 'cache_form', 'cache_menu');
  $cache_tables = array_merge(module_invoke_all('flush_caches'), $core);
  foreach ($cache_tables as $table) {
    cache_clear_all(NULL, $table);
  }


As the first argument of cache_clear_all() is NULL, the code executed in DrupalDatabaseCache::clear() (Drupal 7) is the following one.

if (variable_get('cache_lifetime', 0)) {
  // We store the time in the current user's $user-&gt;cache variable which
  // will be saved into the sessions bin by _drupal_session_write(). We then
  // simulate that the cache was flushed for this user by not returning
  // cached data that was cached before the timestamp.
  $user-&gt;cache = REQUEST_TIME;

  $cache_flush = variable_get('cache_flush_' . $this-&gt;bin, 0);
  if ($cache_flush == 0) {
    // This is the first request to clear the cache, start a timer.
    variable_set('cache_flush_' . $this-&gt;bin, REQUEST_TIME);
  }
  elseif (REQUEST_TIME &gt; ($cache_flush + variable_get('cache_lifetime', 0))) {
    // Clear the cache for everyone, cache_lifetime seconds have
    // passed since the first request to clear the cache.
    db_delete($this-&gt;bin)
        -&gt;condition('expire', CACHE_PERMANENT, '&lt;&gt;')
        -&gt;condition('expire', REQUEST_TIME, '&lt;')
        -&gt;execute();
    variable_set('cache_flush_' . $this-&gt;bin, 0);
  }
}


The code removes only the rows, which are not marked as permanent, and are expired, from the tables returned from hook_flush_caches(), and from various cache tables used from Drupal, including "cache_form." There should not be too much rows in "cache_form"; if that happens, you can reduce the time passed between two consecutive executions of the cron tasks, or execute the following code from a custom module.

cache_clear_all(NULL, 'cache_form');


An alternative is to manually cause the cache to be cleared, using the Devel module, and the menu link it shows.