private int sweep() {
		int nDeallocated = 0;
		long pos;
		gcDone = true;

		for (int i = dbFirstUserId, j = committedIndexSize; i < j; i++) {
			pos = getGCPos(i);

			if (pos != 0
					&& ((int) pos & (dbPageObjectFlag | dbFreeHandleFlag)) == 0) {
				int bit = (int) (pos >>> dbAllocationQuantumBits);

				if ((blackBitmap[bit >>> 5] & (1 << (bit & 31))) == 0) {
					// object is not accessible
					if (getPos(i) == pos) {
						int offs = (int) pos & (Page.pageSize - 1);
						Page pg = pool.getPage(pos - offs);
						int typeOid = ObjectHeader.getType(pg.data, offs);

						if (typeOid != 0) {
							ClassDescriptor desc = findClassDescriptor(typeOid);
							nDeallocated += 1;

							if (Btree.class.isAssignableFrom(desc.cls)) {
								Btree btree = new Btree(pg.data,
										ObjectHeader.sizeof + offs);
								pool.unfix(pg);
								btree.assignOid(this, i, false);
								btree.deallocate();
							}
							else {
								int size = ObjectHeader.getSize(pg.data, offs);
								pool.unfix(pg);
								freeId(i);
								objectCache.remove(i);
								cloneBitmap(pos, size);
							}

							if (listener != null) {
								listener.deallocateObject(desc.cls, i);
							}
						}
					}
				}
			}
		}

		greyBitmap = null;
		blackBitmap = null;
		allocatedDelta = 0;
		gcActive = false;

		if (listener != null) {
			listener.gcCompleted(nDeallocated);
		}

		return nDeallocated;
	}