开发者

Does PHP's APC reclaim memory after apc_delete() is called?

More generally, d开发者_运维知识库oes anyone know where the way APC works internally is documented?


The short answer is yes, it appears to free and reclaim memory. Below I have listed the main functions involved, descending further into the call stack as we go:

  1. apc_delete
  2. apc_cache_user_delete
  3. remove_slot
  4. free_slot
  5. apc_sma_free
  6. sma_deallocate

apc_delete

// taken from the file php_apc.c
// http://php-apc.sourcearchive.com/documentation/3.0.18/php__apc_8c-source.html

/* {{{ proto mixed apc_delete(string key)
 */
PHP_FUNCTION(apc_delete) {
    char *strkey;
    int strkey_len;

    if(!APCG(enabled)) RETURN_FALSE;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &strkey, &strkey_len) == FAILURE) {
        return;
    }

    if(!strkey_len) RETURN_FALSE;

    if(apc_cache_user_delete(apc_user_cache, strkey, strkey_len + 1)) {
        RETURN_TRUE;
    } else {
        RETURN_FALSE;
    }
}
/* }}} */

apc_cache_user_delete

// taken from the file apc_cache.c
// http://php-apc.sourcearchive.com/documentation/3.0.18/apc__cache_8c-source.html

/* {{{ apc_cache_user_delete */
int apc_cache_user_delete(apc_cache_t* cache, char *strkey, int keylen)
{
    slot_t** slot;

    LOCK(cache);

    slot = &cache->slots[string_nhash_8(strkey, keylen) % cache->num_slots];

    while (*slot) {
        if (!memcmp((*slot)->key.data.user.identifier, strkey, keylen)) {
            remove_slot(cache, slot);
            UNLOCK(cache);
            return 1;
        }
        slot = &(*slot)->next;
    }

    UNLOCK(cache);
    return 0;
}
/* }}} */

remove_slot

// taken from the file apc_cache.c
// http://php-apc.sourcearchive.com/documentation/3.0.18/apc__cache_8c-source.html

/* {{{ remove_slot */
static void remove_slot(apc_cache_t* cache, slot_t** slot)
{
    slot_t* dead = *slot;
    *slot = (*slot)->next;

    cache->header->mem_size -= dead->value->mem_size;
    cache->header->num_entries--;
    if (dead->value->ref_count <= 0) {
        free_slot(dead);
    }
    else {
        dead->next = cache->header->deleted_list;
        dead->deletion_time = time(0);
        cache->header->deleted_list = dead;
    }
}
/* }}} */

free_slot

// taken from the file apc_cache.c
// http://php-apc.sourcearchive.com/documentation/3.0.18/apc__cache_8c-source.html

/* {{{ free_slot */
static void free_slot(slot_t* slot)
{
    if(slot->value->type == APC_CACHE_ENTRY_USER) {
        apc_sma_free((char *)slot->key.data.user.identifier);
    } else if(slot->key.type == APC_CACHE_KEY_FPFILE) {
        apc_sma_free((char *)slot->key.data.fpfile.fullpath);
    }
    apc_cache_free_entry(slot->value);
    apc_sma_free(slot);
}
/* }}} */

apc_sma_free

// taken from the file apc_sma.c
// http://php-apc.sourcearchive.com/documentation/3.0.18/apc__sma_8c-source.html

/* {{{ apc_sma_free */
void apc_sma_free(void* p)
{
    int i;
    size_t offset;
    size_t d_size;
    TSRMLS_FETCH();

    if (p == NULL) {
        return;
    }

    assert(sma_initialized);

    for (i = 0; i < sma_numseg; i++) {
        LOCK(((header_t*)sma_shmaddrs[i])->sma_lock);
        offset = (size_t)((char *)p - (char *)(sma_shmaddrs[i]));
        if (p >= sma_shmaddrs[i] && offset < sma_segsize) {
            d_size = sma_deallocate(sma_shmaddrs[i], offset);
            if (APCG(mem_size_ptr) != NULL) { *(APCG(mem_size_ptr)) -= d_size; }
            UNLOCK(((header_t*)sma_shmaddrs[i])->sma_lock);
#ifdef VALGRIND_FREELIKE_BLOCK
            VALGRIND_FREELIKE_BLOCK(p, 0);
#endif
            return;
        }
        UNLOCK(((header_t*)sma_shmaddrs[i])->sma_lock);
    }

    apc_eprint("apc_sma_free: could not locate address %p", p);
}
/* }}} */

sma_deallocate

// taken from the file apc_sma.c
// http://php-apc.sourcearchive.com/documentation/3.0.18/apc__sma_8c-source.html

/* {{{ sma_deallocate: deallocates the block at the given offset */
static size_t sma_deallocate(void* shmaddr, size_t offset)
{
    header_t* header;   /* header of shared memory segment */
    block_t* cur;       /* the new block to insert */
    block_t* prv;       /* the block before cur */
    block_t* nxt;       /* the block after cur */
    size_t size;        /* size of deallocated block */

    offset -= ALIGNWORD(sizeof(struct block_t));
    assert(offset >= 0);

    /* find position of new block in free list */
    cur = BLOCKAT(offset);
    prv = BLOCKAT(ALIGNWORD(sizeof(header_t)));

    CHECK_CANARY(cur);

#ifdef __APC_SMA_DEBUG__
    CHECK_CANARY(prv);
    fprintf(stderr, "free(%p, size=%d,id=%d)\n", cur, (int)(cur->size), cur->id);
#endif
    while (prv->next != 0 && prv->next < offset) {
        prv = BLOCKAT(prv->next);
#ifdef __APC_SMA_DEBUG__
        CHECK_CANARY(prv);
#endif
    }

    CHECK_CANARY(prv);

    /* insert new block after prv */
    cur->next = prv->next;
    prv->next = offset;

#ifdef __APC_SMA_DEBUG__
    CHECK_CANARY(cur);
    cur->id = -1;
#endif

    /* update the block header */
    header = (header_t*) shmaddr;
    header->avail += cur->size;
    size = cur->size;

    if (((char *)prv) + prv->size == (char *) cur) {
        /* cur and prv share an edge, combine them */
        prv->size += cur->size;
        prv->next = cur->next;
        RESET_CANARY(cur);
        cur = prv;
    }

    nxt = BLOCKAT(cur->next);

    if (((char *)cur) + cur->size == (char *) nxt) {
        /* cur and nxt shared an edge, combine them */
        cur->size += nxt->size;
        cur->next = nxt->next;
#ifdef __APC_SMA_DEBUG__
        CHECK_CANARY(nxt);
        nxt->id = -1; /* assert this or set it ? */
#endif
        RESET_CANARY(nxt);
    }
    header->nfoffset = 0;  /* Reset the next fit search marker */

    return size;
}
/* }}} */

The core files can be found here: http://php-apc.sourcearchive.com/documentation/3.0.18/files.html


Yes, but: If you do lots of store and delete memory gets fragmented. And apc doesn't have a way to "defragment" memory and after some time it might not find enough free space where the new var fits in. So the memory is free but can't be used.

If that happens apc usually deletes everything. (that can be configured)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜