在调用apc_delete()之后,PHP的APC是否会回收内存?

时间:2010-05-21 18:02:33

标签: php performance memory-management apc

更一般地说,是否有人知道APC内部工作方式的位置?

2 个答案:

答案 0 :(得分:2)

简短的回答是肯定的,它似乎可以释放和回收记忆。下面我列出了所涉及的主要功能,我们继续进一步下降到调用堆栈中:

  1. apc_delete
  2. apc_cache_user_delete
  3. remove_slot
  4. free_slot
  5. apc_sma_free
  6. sma_deallocate
  7. 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;
    }
    /* }}} */
    

    核心文件可以在这里找到: http://php-apc.sourcearchive.com/documentation/3.0.18/files.html

答案 1 :(得分:1)

是的,但是:如果你做了很多商店和删除内存变得支离破碎。并且apc没有办法对内存进行“碎片整理”,经过一段时间后,它可能找不到新的var适合的空闲空间。所以内存是免费的,但不能使用。

如果发生这种情况,apc通常会删除所有内容。 (可以配置)